我正在尝试测试一个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(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)>'```
我错过了什么,或者我是在咆哮完全错误的树?
版本信息: Rails 1.9.3 Rspec 2.11.0
更新:基于答案
it "registers an unknown user" do
unknown_phone_number = "0000000000"
expect {
post :create, twiml_message(unknown_phone_number, "YES", "To" => twilio_phone_number)
}.to change(Card, :count).by(1)
open_last_text_message_for unknown_phone_number
current_text_message.should have_body "Welcome to OnTab. You are now registered with a test account. To get started text TAB to open a tab."
end
it "registers an unknown user" do
unknown_phone_number = "0000000000"
expect {
post :create, twiml_message(unknown_phone_number, "YES", "To" => twilio_phone_number)
}.to change(Customer, :count).by(1)
open_last_text_message_for unknown_phone_number
current_text_message.should have_body "Welcome to OnTab. You are now registered with a test account. To get started text TAB to open a tab."
end
it "registers an unknown user" do
unknown_phone_number = "0000000000"
expect {
post :create, twiml_message(unknown_phone_number, "YES", "To" => twilio_phone_number)
}.to change(User, :count).by(1)
open_last_text_message_for unknown_phone_number
current_text_message.should have_body "Welcome to OnTab. You are now registered with a test account. To get started text TAB to open a tab."
end
但这会使后期动作三次。有没有办法做到这一点,但只执行一次POST?
答案 0 :(得分:2)
您可能希望将此类测试作为集成或请求规范。控制器应该更多地关于断言传递给模型的消息和设置视图/返回状态。但是,为了回答这个问题,response
对象上没有call
方法。它是返回的状态 - 事情已经发生了变化。你想断言post
做了改变。
expect change
匹配器需要附加到expect的块形式:
it do
expect{ post :create, ... }.to change(User, :count).by(1)
end
您当前的主题不是预期阻止,而是post
操作的返回值。因此,隐含主题不适用于change
。另外,正如我上面所说,出于同样的原因,你不能使用response.should
。您需要使用阻止表格。
对于此类测试,由于RSpec如何处理expect{}.
与should
,您将无法使用隐式主题。
另外,可以说,使主题成为预期阻碍会改变责任和角色。通常,被测对象是一个对象。通过将其设置为动作,您正在改变这一点,并可能会让其他人感到困惑。在这种情况下,这可能看起来很奇怪,但这是由于Rails以及您与控制器对象的交互方式。
是的,它会发出三个post
个请求。我假设你只想提出一个请求,因为“性能”。这可能是一个问题,但您可以采取许多措施来帮助降低性能,而不是简单地发出一个请求。
加速测试的一个理念是在控制器测试中存根Active Record,以保持简短和快速。然后将集成规范用于您正在讨论的测试类型(阅读http://www.andylindeman.com/2012/11/11/rspec-rails-and-capybara-2.0-what-you-need-to-know.html)。是的,集成测试通常较慢;这是进行全栈测试的代价。
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