Ruby单元测试技术,模拟和存根 [英] Ruby Unit testing techniques, Mocking and Stubbing

查看:83
本文介绍了Ruby单元测试技术,模拟和存根的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经被招募为软件开发人员,我正尝试使用红宝石的RSPEC和RR进行单元测试,但是很难决定具体的策略,主要是因为我被分配为代码编写单元测试已经写了.

I've been recruited as a SW Dev and I'm trying to get into Unit Testing with RSPEC and RR in ruby but having an hard time deciding on a specific strategy mainly because I was assigned to write unit tests to a code which is already written.

请考虑以下代码,这是一个名为method1的大型方法的一部分:

Consider the following code which is a part of a big method called method1:

  if (["5234541252", "6236253223"].include?(self.id))
    self.DoCheck
    logs.add 'Doing check', "id = #{self.id}"
    return
  end

该方法的这一部分的相关单元测试应该是这样的:

The relevant unit test for this part of the method would've been something like:

"should do check only if id = 5234541252 or 6236253223"

但是我遇到了一些问题,基本上涉及最佳实践,例如:

But i'm running into a few questions, basically involving best practices, for example:

如何检查是否使用RR和RSPEC在方法1"中调用了DoCheck?

How can I check if DoCheck has been called from within "method1" using RR and RSPEC?

我已经尝试过使用dont_allow(Object).DoCheck,但是它不起作用.

I've tried using dont_allow(Object).DoCheck but it won't work.

describe :do_route do
  it "should do check only if id = 5234541252 or 6236253223" do
  user = Factory(:User)
  user.id = "5234541252"

  dont_allow(user).DoCheck
  user.method1
end

还有其他方法可以得出是否调用"DoCheck"的结论吗?

Is there any other way to conclude if "DoCheck" was called or not?

推荐答案

您可以在测试中的对象上使用部分模拟"技术.这意味着您需要设置期望user.method1user发送DoCheck消息. RSpec可以使用should_receive()方法设置此期望值.如果无法达到预期,则测试将失败.

You can use 'Partial Mocking' technique on your object under tests. This means you need to set expectation that user.method1 sends DoCheck message to the user. RSpec can set this expectation with should_receive() method. The test will fail if expectation won't be met.

尝试以下代码:

describe :do_route do
  it "should do check if id = 5234541252 or 6236253223" do
    user = Factory(:User)
    user.id = "5234541252"

    user.should_receive(:DoCheck) # set expectation that DoCheck will be called

    user.method1  # execute
  end
end

对于 RR ,这种期望可能看起来像这样:

With RR this expectation may look like this:

describe :do_route do
  it "should do check if id = 5234541252 or 6236253223" do
    user = Factory(:User)
    user.id = "5234541252"

    mock(user).DoCheck # set expectation that DoCheck will be called

    user.method1  # execute
  end
end

更新

但是要小心使用模拟对象和部分模拟,因为它们会使您的测试代码与被测代码的当前行为紧密耦合.如果将来要重构此代码,则可能会遇到很多失败的测试(那些使用模拟的测试).尝试在没有模拟(输入-输出)的情况​​下测试代码,并仅在模拟清楚说明被测类的意图时才使用模拟.当您用模拟编写测试时,请始终问自己一个问题,您是否真的需要断言该方法调用另一个方法,或者您真正关心的是该方法或其他内容的输出.

Update

But be careful with usage of mock objects and partial mocks because they make your test code tightly coupled to the current behavior of the code under tests. If you are going to refactor this code in the future you will possibly get a lot of failing tests (those that use mocks). Try testing code without mocks (input-output) and use mocks only if they clearly explain intent of the class under test. When you write test with mock always ask yourself do you really need to assert that this method calls another method or what you really care is the output of the method or something else.

希望这会有所帮助!

这篇关于Ruby单元测试技术,模拟和存根的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆