Ruby on rails Rails Rspec测试中的多重期望
我正在尝试测试一个ruby控制器方法,我希望数据库中有多个方面会发生变化Ruby on rails Rails Rspec测试中的多重期望,ruby-on-rails,rspec,Ruby On Rails,Rspec,我正在尝试测试一个ruby控制器方法,我希望数据库中有多个方面会发生变化 context "With an unknown user" do let(:unknown_phone_number) { "0000000000" } subject {post :create, twiml_message(unknown_phone_number, "YES", "To" => twilio_phone_number) } it { response.should change(
context "With an unknown user" do
let(:unknown_phone_number) { "0000000000" }
subject {post :create, twiml_message(unknown_phone_number, "YES", "To" => twilio_phone_number) }
it { response.should change(Card, :count).by(1) }
it { should change(User, :count).by(1) }
it { should change(Customer, :count).by(1) }```
end
给出了错误
NoMethodError: undefined method `call' for #<ActionController::TestResponse:0x007fbd5d643030> ./spec/controllers/api/v1/sms_controller_spec.rb:25:in `block (4 levels) in <top (required)>'```
但这会运行三次后期操作。是否有任何方法可以做到这一点,但只能执行POST一次?您可能希望将这种类型的测试作为集成或请求规范。控制器应该在断言传递给模型的消息以及设置查看/返回状态方面做得更多。不过,为了回答这个问题,
response
对象上没有调用
方法。这是返回的状态-事情已经改变了。您希望断言post
执行更改
匹配器需要附加到expect的块形式:
it do
expect{ post :create, ... }.to change(User, :count).by(1)
end
当前主题不是期望块,而是post
操作的返回值。因此隐式主语不适用于change
。另外,正如我上面所说的,出于同样的原因,您不能使用response.should
。您需要使用块形式
对于这种类型的测试,由于RSpec处理expect{}.
与should
的方式不同,您将无法使用隐式主题
此外,可以说,将主题设置为期望块将改变职责和角色。一般来说,被测试的对象是一个对象。通过将其设置为一个动作,您正在改变这一点,并且很可能会让其他人感到困惑。在这种情况下,这可能看起来很奇怪,但这是因为Rails以及您如何与控制器对象交互
根据问题更改进行更新:
是的,它将发出三个post
请求。我假设您只想提出一个请求,因为“性能”。这可能是一个问题,但您可以做很多事情来帮助降低性能,而不是简单地提出一个请求
加快测试速度的一个理念是在控制器测试中存根活动记录,这样可以使事情保持简短和快速。然后,集成规范将用于您正在讨论的测试类型(请阅读)。是的,集成测试通常较慢;这是进行完整堆栈测试的代价
RSpec的理念是“测试一件事”。您希望每次都重新执行被测试的对象/方法。这可确保不会出现交叉测试污染,从而导致错误结果。正如本文所写,我想说的是,您已经违反了这一规则,正在测试数据库更新和文本消息预期
context 'registering a new user' do
it 'saves the user in the database' do
unknown_phone_number = '000'
new_card = mock_model(Card)
expect(Card).to receive(:new).and_return(new_card)
expect(new_card).to receive(:save).and_return(true)
post :create #...
end
it 'sends a welcome message to the phone' do
# You can stub the text class here and assert on messages passed
# As you probably trust that if the message is passed the text message code
# does what it was designed to do (you have unit tests for it right?)
end
end
我同意,我可能应该在模型级别这样做。第一行“it”中的响应是我试图调试它。没有它我也会犯同样的错误。我先尝试了你是第二个符号,但我想检查多个东西,我认为我不能链接“改变”。@Chainlink你不能也不应该链接
改变期望。在RSpec中,习惯用法是每个测试一个期望值。在有响应和无响应的情况下都尝试了它,我得到了相同的错误。您不应该使用响应。expect{}.to change()
版本确实有效。如果你在阅读我更新的例子后仍然有问题,请发布你的新规范块。根据我对你答案的理解更新问题。
context 'registering a new user' do
it 'saves the user in the database' do
unknown_phone_number = '000'
new_card = mock_model(Card)
expect(Card).to receive(:new).and_return(new_card)
expect(new_card).to receive(:save).and_return(true)
post :create #...
end
it 'sends a welcome message to the phone' do
# You can stub the text class here and assert on messages passed
# As you probably trust that if the message is passed the text message code
# does what it was designed to do (you have unit tests for it right?)
end
end