如何测试是否在RSpec中调用方法但不覆盖返回值

Jay*_*rio 6 rspec ruby-on-rails

已经类似的问题,但它们都会覆盖返回值,nil除非.and_return被调用

问题

我想知道是否有办法只检查一个方法是否被调用使用expect_any_instance_of(Object).to receive(:somemethod)并且它正常运行而不会覆盖或影响返回值.somemethod.

  • rspec的-3.4.0
  • 铁轨4.2

考虑以下:

# rspec
it 'gets associated user' do
  expect_any_instance_of(Post).to receive(:get_associated_user)
  Manager.run_processes
end

# manager.rb
class Manager
  def self.run_processes
    associated_user = Category.first.posts.first.get_associated_user
    associated_user.destroy!
  end
end
Run Code Online (Sandbox Code Playgroud)

上面的规范虽然会起作用,因为它:get_associated_user被称为run_processes,但它NoMethodError: undefined method 'destroy!' for NilClass正好引起,因为我嘲笑了:get_associated_userPost的任何实例.

我可以添加一个.and_return方法,expect_any_instance_of(Post).to receive(:get_associated_user).and_return(User.first)以便它可以工作而不会引发该错误,但这已经是一个模拟的返回值(可能会影响它下面的其余代码),而不是它应该在当时返回的正确的期望值该方法被调用.

但是.and_return(correct_user) ,我可以指定correct_user用户在哪里将返回相同的返回值,就好像它已正常运行一样.但是,这需要我模拟序列中的每个返回值,Category.first.posts.first.get_associated_user以便它能正常工作.实际问题比上面复杂得多,因此在我的情况下,存根不是真正可行的解决方案.

max*_*max 15

您可以and_call_original在流畅的界面上使用"将"收到的消息"传递"到原始方法.

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

expect_any_instance_of(Post).to receive(:get_associated_user).and_call_original
Run Code Online (Sandbox Code Playgroud)

然而,使用expect_any_instance_of可能会告诉你,你有代码味道,你应该测试行为 - 而不是实现.

# test what it does - not how it does it.
it 'destroys the associated user' do
  expect { Manager.run_processes }.to change(Category.first.posts.first.users, :count).by(-1)
end
Run Code Online (Sandbox Code Playgroud)

  • 几个月来我一直在寻找这个!:)我怎么能错过这个.非常感谢!你是对的,`expect_any_instance_of`并不总是准确而且特定于测试,因为正是"任何实例"这个词.我只是有一个特定的情况,我想测试"实现"而不是"行为",因为它正在操纵图像,我想不出一种正确测试图像已按预期更新的方法.因此,我刚刚测试了该方法被调用,并祈祷它有效:) (2认同)