ruby-on-rails - 如何测试复合 Rails 模型范围?
问题描述
考虑以下模型:
class Model < ActiveRecord::Base
scope :a, -> () { where(a: 1) }
scope :b, -> () { where(b: 1) }
scope :a_or_b, -> () { a.or(b) }
end
现在要正确测试每个范围,我至少会为每个可能的变量提供一个匹配的示例和一个不匹配的示例。像这样的东西:
RSpec.describe Model do
describe "scopes" do
describe ".a" do
subject { Model.a }
let!(:with_a_0) { create(:model, a: 0) }
let!(:with_a_1) { create(:model, a: 1) }
it { should_not include(with_a_0) }
it { should include(with_a_1) }
end
describe ".b" do
subject { Model.b }
let!(:with_b_0) { create(:model, b: 0) }
let!(:with_b_1) { create(:model, b: 1) }
it { should_not include(with_b_0) }
it { should include(with_b_1) }
end
describe ".a_or_b" do
subject { Model.a_or_b }
let!(:with_a_0_and_b_0) { create(:model, a: 0, b: 0) }
let!(:with_a_0_and_b_1) { create(:model, a: 0, b: 1) }
let!(:with_a_1_and_b_0) { create(:model, a: 1, b: 0) }
let!(:with_a_1_and_b_1) { create(:model, a: 1, b: 1) }
it { should_not include(with_a_0_and_b_0) }
it { should include(with_a_0_and_b_1) }
it { should include(with_a_1_and_b_0) }
it { should include(with_a_1_and_b_1) }
end
end
end
但是感觉就像我在重新测试.a
并.b
在.a_or_b
测试中,如果我再次创作它,用另一个范围,它会变得越来越大。
处理这个问题的明智方法是什么?
另外:这是单元测试还是集成测试?
解决方案
这是一个艰难的。我想说你必须在全面覆盖和你的规格可读性之间找到一个亚里士多德的平均值。测试影响示波器行为方式的所有可能状态组合可能是不合理的。
它也不是真正的单元测试,因为它与 DB 层耦合。
我的方法是这样的:
不要测试简单的范围(如a
和b
在您的示例中),相信 AR 已经过良好测试,让您的范围名称清晰并保留它。
在更复杂的范围内,您可以颠倒编写测试的方式:创建一次样本,然后为不同的范围定义期望(并使样本名称非常清晰,就像您已经在做的那样)。
这将稍微减小规范的大小,并且更容易阅读这些规范。但是,如果您想全面覆盖每个范围,它仍然会增加规格大小。
RSpec.describe Model do
describe "scopes" do
let!(:with_a_0_and_b_0) { create(:model, a: 0, b: 0) }
let!(:with_a_0_and_b_1) { create(:model, a: 0, b: 1) }
let!(:with_a_1_and_b_0) { create(:model, a: 1, b: 0) }
let!(:with_a_1_and_b_1) { create(:model, a: 1, b: 1) }
it { expect(described_class.a).to include(with_a_1_and_b_1).and include(with_a_1_and_b_1) }
it { expect(described_class.a).not_to include(with_a_0_and_b_0) }
# you get the idea
为了使这个^更具可读性,我建议创建一个自定义 matcher,您可以像这样使用:
it do
expect(described_class.a)
.to retrieve(with_a_1_and_b_0, with_a_1_and_b_1)
.and not_retrieve(with_a_0_and_b_0, with_a_0_and_b_1)
end
推荐阅读
- php - php文件中的“使用”语句
- hyperledger-composer - 更改区块链模型后如何更新 Hyperledger Composer REST 服务器?
- voltdb - VoltDB Kafka 导入器
- php - 来自 php 的 PDF 生成器
- localdb - 如果缺少,localdb 不会创建数据库文件
- regex - 正则表达式将 C 样式的多行注释转换为单个块注释
- c# - 如何解释 BenchmarkDotNet 和 dotMemory 的结果?
- php - Laravel 服务容器:父类的上下文绑定,适用于所有子类
- firebase - 在 React Native 中注册并推送数据到 Firebase
- c# - 输入文本的参数太少 - C# Discord bot