2014-03-26 3 views
7

Я пытаюсь понять тесты в унаследованном приложении, и мне нужна помощь.Rspec mocks, может 'ожидать' также заглушить метод как побочный эффект?

Есть много спецификации таких групп, как это один (вид спецификации):

let(:job_post) { FactoryGirl.create(:job_post) } 

# ... 

before do 
    expect(view).to receive(:job_post).at_least(:once).and_return(job_post) 
end 

it "should render without error" do 
    render 
end 

... с job_post будучи вспомогательный метод, определенный на контроллере. (да, они могли использовать переменные @instance, и я в процессе рефакторинга).

Теперь, на мой взгляд, использование expect внутри блока before неверно. Давайте забудем об этом на секунду.

Обычно тест выше зеленый.
Однако, если я удаляю линии expect, тест не проходит. Похоже, что в этом случае expect укутывает метод на вид. Фактически, замена expect на allow, похоже, имеет тот же эффект.

Я думаю, что то, что происходит в том, что обычно - при запуске с сервером - вид будет вызывать job_posts и сообщение будет земля на вспомогательном методе на контроллере, который является ожидаемым поведением.

Здесь, однако, expect устанавливает ожидаемое значение и в то же время накладывает метод на view с фиксированным возвращаемым значением. Так как шаблон вида будет, вызовите этот метод, тест пройдет.

О том, что неожиданный «заглушке» побочный эффект expect, я нашел это в rspec-mocks readme:

(...) Мы можем также установить сообщение ожидания, так что пример не работает, если находка не называется:

person = double("person") 
expect(Person).to receive(:find) { person } 

RSpec заменяет метод мы заглушек или насмешки со своим собственным тест-двойной как метод. В конце примера RSpec проверяет ожидания сообщений, а затем восстанавливает исходные методы.

Есть ли у кого-нибудь опыт в этом конкретном использовании метода?

ответ

17

Ну, вот что expect().to receive()! Это (не так) новый expectation syntax из rspec, который заменяет should_receive API

expect(view).to receive(:job_post).at_least(:once).and_return(job_post) 

эквивалентно

view.should_receive(:job_post).at_least(:once).and_return(job_post) 

и этот API устанавливает ожидание и возвращаемое значение. Это поведение по умолчанию.На самом деле вызов оригинальный метод, а также, вы должны явно сказать так:

view.should_receive(:job_post).at_least(:once).and_call_original 

На некоторые другие вопросы:

(да, они могли бы использовать @instance переменные, и я в процессе реорганизации).

let API очень распространены в RSpec тестирования, и может быть лучше, чем @instance переменных во многих случаях (например, - это лень, поэтому он работает только тогда, когда это необходимо, и оно memoized, поэтому он работает на самый один раз).

Фактически, замена expect на allow, похоже, имеет такой же эффект.

Синтаксис allow заменяет метод stub в старом RSpec синтаксиса, так что да, он имеет тот же эффект, но разница в том, что он не подведет тест, если погасил метод не называется ,


Как ОП запрошенной - некоторые объяснения о should_receive - юнит-тесты, как ожидается, запустить в изоляции. Это означает, что все, что не является непосредственно частью вашего теста, не следует проверять. Это означает, что HTTP-запросы, IO-чтения, внешние службы, другие модули и т. Д. Не являются частью теста, и для этого теста из вы должны принять, что они работают правильно.

Что вы должны включать в тестах, что эти HTTP вызовы, IO читает, а внешние услуги являются называется правильно. Для этого вы устанавливаете сообщение ожидания - вы ожидаете проверенный метод до вызывает определенный метод (фактическая функциональность которого выходит за рамки теста). Итак, вы ожидаете службы , чтобы получить вызов метода с правильными аргументами один или несколько раз (вы можете явно ожидать, сколько раз он должен быть вызван), а взамен того, что он фактически вызывается, он, и в соответствии с тестом, установите его возвращаемое значение.

+0

спасибо. Когда я упоминал переменные экземпляра, я фактически говорил о контроллерах, а не о тестах. Кто работал над передо мной проектом, имел отвращение к представлениям с использованием переменных @instance контроллеров и создал для них все аксессоры. – tompave

+0

Кроме того, большой ответ ... но не могли бы вы расшириться на 'should_receive'? Я всегда использовал 'stub' и' allow', и я всегда предполагал, что 'expect (obj) .to receive' задает математическое ожидание __only__. – tompave

+0

Спасибо за разъяснение. Да, я знаю о важности макетов и заглушек в модульных тестах. Тем не менее, я всегда явно использовал 'stub/allow' для заглушения метода, а затем' shout_receive/expect(). Получать 'для проверки сообщения. Я был просто удивлен, что 'expect' обрабатывает его автоматически ... и я считаю это немного запутанным, если честно. – tompave

0

Rspec - это мета-жемчуг, который зависит от rspec-core, rspec-ожиданий и rspec-mocks gems. Rspec-mocks - это тестовая двойная структура для rspec с поддержкой заглушек методов, подделок и ожиданий от сообщений о сгенерированных двойниках и реальных объектах.

allow().to receive 

является использование 'метода окурки', однако

expect().to receive 

является использование 'ожидания сообщений'

Вы можете обратиться к Doc для более подробной информации

1

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

https://relishapp.com/rspec/rspec-mocks/v/2-14/docs/message-expectations/calling-the-original-method

Например, я когда-то хотел шпионить метод, но и вызвать функцию еще она другая сторона влияет. Это действительно помогло.

https://relishapp.com/rspec/rspec-mocks/v/2-14/docs/message-expectations/calling-the-original-method

Смежные вопросы