我为我的范围创建了rspec测试(scope1
,scope2
和scope3
)并且它们按预期传递但我还想为类方法添加一些测试具有从我的控制器实际调用的内容(控制器通过此类方法间接调用范围):
def self.my_class_method(arg1, arg2)
scoped = self.all
if arg1.present?
scoped = scoped.scope1(arg1)
end
if arg2.present?
scoped = scoped.scope2(arg2)
elsif arg1.present?
scoped = scoped.scope3(arg1)
end
scoped
end
当我知道它们已经通过时,为这个类方法中的每个场景运行相同的范围测试似乎有点多余,所以我假设我真的只需要确保根据传入的args调用/应用不同的范围这个类方法。
有人可以就这个rspec测试的样子提出建议。
我认为这可能与
有关expect_any_instance_of(MyModel.my_class_method(arg1, nil)).to receive(:scope1).with(arg1, nil)
但这不起作用。
我还要感谢确认,在我已经测试过范围的情况下,这是测试这种情况所必需的全部内容。
答案 0 :(得分:0)
您编写的Rspec代码实际上是在测试方法的内部实现。您应该测试该方法返回您希望它返回给定参数的内容,而不是它以某种方式执行它。这样,您的测试就会变得不那么脆弱。例如,如果您更改了scope1
被调用的内容,则您不必重写my_class_method
次测试。
我会通过创建类的多个实例然后使用各种参数调用该方法并检查结果是否符合预期来实现。
我不知道scope1
和scope2
做了什么,所以我做了一个示例,其中参数是模型的name
属性,范围方法只是检索所有模型除了具有该名称的模型。显然,无论你的真实论点和scope
方法是什么,你都应该把它放在你的测试中,你应该相应地修改预期的结果。
我将to_ary
方法用于预期结果,因为self.all
调用实际上返回了ActiveRecord关联,因此不会与预期的数组匹配。您可以使用includes
和does_not_includes
代替eq
,但也许您关心订单或其他内容。
describe MyModel do
describe ".my_class_method" do
# Could be helpful to use FactoryGirl here
# Also note the bang (!) version of let
let!(:my_model_1) { MyModel.create(name: "alex") }
let!(:my_model_2) { MyModel.create(name: "bob") }
let!(:my_model_3) { MyModel.create(name: "chris") }
context "with nil arguments" do
let(:arg1) { nil }
let(:arg2) { nil }
it "returns all" do
expected = [my_model_1, my_model_2, my_model_3]
expect_my_class_method_to_return expected
end
end
context "with a first argument equal to a model's name" do
let(:arg1) { my_model_1.name }
let(:arg2) { nil }
it "returns all except models with name matching the argument" do
expected = [my_model_2, my_model_3]
expect_my_class_method_to_return expected
end
context "with a second argument equal to another model's name" do
let(:arg1) { my_model_1.name }
let(:arg2) { my_model_2.name }
it "returns all except models with name matching either argument" do
expected = [my_model_3]
expect_my_class_method_to_return expected
end
end
end
end
private
def expect_my_class_method_to_return(expected)
actual = described_class.my_class_method(arg1, arg2).to_ary
expect(actual).to eq expected
end
end