2015-06-02 14 views
1

Я создал тесты rspec для своих областей (scope1, scope2 и scope3), и они проходят как ожидалось, но я также хотел бы добавить некоторые тесты для метода класса, который у меня есть что на самом деле вызывается из моего контроллера (контроллер вызывает области косвенно через этот метод класса):Использование rspec для проверки методов класса вызывает вызовы

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 

Это кажется немного излишним для выполнения тех же тестов области видимости для каждого сценария в этом методе класса, когда я знаю, что они уже поэтому я предполагаю, что мне действительно нужно только обеспечить, чтобы различные области назывались/применялись в зависимости от аргументов, передаваемых в этот метод класса.

Может кто-нибудь посоветует, как будет выглядеть этот тест rspec.

Я думал, что это может быть что-то вдоль линий

expect_any_instance_of(MyModel.my_class_method(arg1, nil)).to receive(:scope1).with(arg1, nil) 

, но это не работает.

Я также благодарен за подтверждение того, что это все, что необходимо для проверки в этой ситуации, когда я уже проверил области, так или иначе, будет реанимация.

ответ

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 
+0

Thanks @ rob-w. Мне просто интересно, если у меня есть тесты уже для каждой из областей, следует ли их изменить, чтобы использовать 'shared_examples' /' behaves_like', чтобы их можно было повторно использовать соответствующим образом для этого метода класса на основе аргументов, применяемых к классу метод ... если это имеет смысл? – user1116573

+0

@ user1116573 Да, это имеет смысл и приведет к очень чистому тестовому коду. Просто имейте в виду, что вы будете связывать тесты с методами «scope1» и «scope2» через 6 месяцев, если вы или кто-то другой измените то, что «scope1» выполняет и исправляет тесты «scope1» соответственно, тесты «my_class_method» 'пройдет и. Это может быть хорошо или плохо, в зависимости от бизнес-логики. –