Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails Rails Rspec测试中的多重期望_Ruby On Rails_Rspec - Fatal编程技术网

Ruby on rails Rails Rspec测试中的多重期望

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(

我正在尝试测试一个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)>'```

但这会运行三次后期操作。是否有任何方法可以做到这一点,但只能执行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