代码之家  ›  专栏  ›  技术社区  ›  xetra11

stubbed方法应根据spock中给定的模拟参数返回值

  •  1
  • xetra11  · 技术社区  · 6 年前

    我希望有不同的返回结果-取决于方法的给定模拟参数。请考虑以下代码片段以遵循我的意图

    class ExampleSpec extends Specification {
    
        def "should return second value of list of return values"() {
            given:
            Person personBob = Mock()
            Person personJackson = Mock()
            PersonHelper stubbedPerson = Stub()
    
            stubbedPerson.getNameOfBrother(personBob) >> "Billy Bob";
            stubbedPerson.getNameOfBrother(personJackson) >> "Tommy Jackson";
    
            when:
            String actual = stubbedPerson.getNameOfBrother(personBob)
            String actual2 = stubbedPerson.getNameOfBrother(personJackson)
    
            then:
            actual == "Billy Bob" // true
            actual2 == "Tommy Jackson" // false "Billy Bob"
        }
    
    }
    

    测试失败,因为第二次调用var actual2 仍然返回 比利鲍勃 而不是 汤米·杰克逊 .我知道有一种方法可以通过调用顺序返回不同的值,但是我想让它依赖于给定的mock。

    使用正常值-没有模拟/存根代理-作为参数值实际上是有效的。我认为斯波克引擎在两个模型之间没有区别。但我对此不确定,因为代理确实有ID作为实例字段。

    1 回复  |  直到 6 年前
        1
  •  3
  •   Szymon Stepniak    6 年前

    对于模拟对象的记录存根是有效的。我添加了简单的 Person PersonHelper 向示例初始化,测试通过:

    import spock.lang.Specification
    
    class ExampleSpec extends Specification {
    
        def "should return second value of list of return values"() {
            given:
            Person personBob = Mock()
            Person personJackson = Mock()
            PersonHelper stubbedPerson = Stub()
    
            stubbedPerson.getNameOfBrother(personBob) >> "Billy Bob";
            stubbedPerson.getNameOfBrother(personJackson) >> "Tommy Jackson";
    
            when:
            String actual = stubbedPerson.getNameOfBrother(personBob)
            String actual2 = stubbedPerson.getNameOfBrother(personJackson)
    
            then:
            actual == "Billy Bob" // true
            actual2 == "Tommy Jackson" // false "Billy Bob"
        }
    
        static class Person {
            String name
        }
    
        static class PersonHelper {
            String getNameOfBrother(Person person) {
                return null
            }
        }
    }
    

    我查过了 spock-core:1.1-groovy-2.4 我是说, spock-core:1.0-groovy-2.4 甚至 spock-core:0.7-groovy-2.0 是的。一切顺利。

    但更重要的是- 这样的测试毫无意义 是的。你根本不测试你的代码。只测试模拟框架是否正确模拟。如果在生产代码中使用spock mock,这个测试可能会有一些意义,但这不是一个有效的假设。

    可能出什么问题?

    想一想这个测试。根据你的 when: 阻止你试图测试 PersonHelper.getNameOfBrother(Person person) 为两个不同的对象返回兄弟的有效名称。现在让我们假设这是对 个人助手 在你的项目中上课。想象一下如果突然实现 getNameOfBrother 方法开始抛出 NullPointerException 因为一些随机的原因。扪心自问-你的单元测试能保护你不受这种情况的影响吗?不。你的测试总是通过的,因为你正在破坏你正在测试的方法。如果您测试一个真正的实现,而您通过了一个真正的 对象,则会通知您 空指针异常 在测试中。否则,当您部署代码时,您将看到它,而某些用户的操作调用此方法时,它将失败。