【问题标题】:How do you check the return value of a method called inside another method rspec?如何检查在另一个方法 rspec 中调用的方法的返回值?
【发布时间】:2021-08-16 00:45:39
【问题描述】:

假设你有一些类似的课程

class Foo
  ...
  public def methodA
    x = methodB(true)
    # other operations (assume x is not the return value of methodA)
  end

  private def methodB(arg)
    if arg
      return 1
    else
      return 0
    end
  end
end

当您为methodA 编写单元测试时,您想检查x 是否被分配了正确的值,这意味着您必须检查对methodB 的调用是否像您预期的那样返回1 .

您将如何在 rspec 中对其进行测试?

现在我有(在 How to test if method is called in RSpec but do not override the return value 的帮助下)

@foo = Foo.new
expect(@foo).to receive(:methodB).with(true).and_call_original

但是我不知道如何验证methodB的实际返回值。

【问题讨论】:

  • 我认为您不能在给定的示例中正确测试methodA。因为即使您测试 method_b 返回预期值,您仍然没有测试 x 是否分配了该值。而且,这些都是实现细节。如果x 被重命名怎么办?如果methodB 被重构怎么办?您的测试不应该关心方法或私有方法的内部结构。相反,测试整个 methodA 的响应或其副作用。
  • methodA 没有返回任何有意义的信息。这是我想要验证的内部发生的事情。 FWIW idrc,它被“分配”给x,我只是想确保在methodA 的整个过程中,当methodB 不可避免地被调用时,它会返回我所期望的——还有副作用,x是本地范围的,所以我没有其他方法可以检查它,就像你可能使用类属性或其他东西一样
  • @notacorn :您所描述的情况基本上是关于methodB 为给定参数返回某个结果。无论您是从methodA 内部还是从不同的地方调用methodB,都应该没有区别。因此,我将简单地编写一个单独的测试用例,仅涉及methodB

标签: ruby unit-testing rspec rspec3


【解决方案1】:

我认为你可以调用私有方法而不是嘲笑?

@foo = Foo.new
result = foo.send(:methodB, true)
expect(result).to eq 1

这基本上是直接测试私有方法。有些人不喜欢这样做,但如果它有很多逻辑,那么直接测试它有时会更容易。我同意@spickermann 的观点,通常最好测试公共方法并将私有方法的实现细节排除在规范之外。

【讨论】:

  • 由于这是methodA的单元测试,我不想直接调用methodB,只调用methodA。我真的只是在问是否可以检查该返回值。
  • 直接测试methodB和调用methodA但只检查methodB返回给methodA的区别在哪里?
【解决方案2】:

不要在单个单元测试中测试多个方法

您做错了,因为您在两种不同的方法之间创建了不必要的依赖关系。相反,您应该重构您的代码,以便:

  1. x 是#methodA 的参数,
  2. x@x@@x 是 methodA 可访问的变量,您可以将其设置为您想要的任何预期值,或者李>
  3. 为这个单元测试存根#methodB。

作为最后一个例子:

describe Foo do
  describe 'methodA' do
    it 'does something when methodB returns 1' do
      # stub the default subject, which is Foo.new
      allow(subject).to receive(:methodB) { 1 }
      expect(subject.methodA).to eq('foo bar baz')
    end
  end
end

此代码未经测试,因为您发布的代码不是一个完整的、可验证的示例。虽然你最好重构你的代码,这样你就根本不用测试嵌套的依赖关系,但使用test doubles or method stubs 肯定是可行的选择。

【讨论】:

  • 所以你是说类 Foo 写错了? methodB 是一种辅助方法来推断一些变量插值,所以我真的不明白为什么使用私有帮助器来分配局部变量是“错误的” - 我不明白你是如何重构它的,作为参数我从这个例子中排除的methodBmethodA 中被确定为前体
  • 所以基本上我的意思是(1)和(2)看起来并不是可行的解决方案,也许(3)是唯一的答案。我仍然很好奇我所要求的(最初,无论如何)在 rspec 中是否可行
  • @notacorn 我的意思是你没有发布一个最小的、完整的、可验证的例子。根据您所做 发布的内容,您一次测试的方法不止一种。不要那样做。当人们在编写实现之前不编写测试时,您遇到的问题很常见。
  • Foo 怎么不是一个最小的完整可验证示例?我只是用... 排除了initialize 方法,否则它将是一个完全有效的ruby 类。
  • @notacorn “这将是一个完全有效的 ruby​​ 类” - 确实如此。测试这个实现也没有任何意义,因为没有发生任何事情。您想要测试的对x 的分配,它是否发生并不重要,因为没有使用 x。
猜你喜欢
  • 2022-01-02
  • 2016-11-16
  • 2020-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-07
  • 2017-10-01
  • 1970-01-01
相关资源
最近更新 更多