Stubbed 方法应该 return 值取决于 Spock 中给定的模拟参数

Stubbed method should return value depending on given mock parameter in Spock

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

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 仍然是 return Billy Bob 而不是 Tommy Jackson.我知道有一种方法可以通过调用顺序 return 不同的值,但我想让它依赖于给定的模拟。

使用正常值 - 没有 Mock/Stub 代理 - 作为参数值确实有效。我假设两个模拟之间的 Spock 引擎没有区别。但我不确定这一点,因为代理确实有 ID 作为实例字段。

郑重声明 - 使用模拟对象存根是可行的。我在您的示例中添加了简单的 PersonPersonHelper 类 并且测试通过了:

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.4spock-core:1.0-groovy-2.4甚至spock-core:0.7-groovy-2.0检查过了。一切正常。

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

What may go wrong?

Think for a second about this test. According to your when: block you are trying to test if PersonHelper.getNameOfBrother(Person person) returns a valid name of a brother for two different objects. Now let's assume that this is the only test of a PersonHelper class in your project. Imagine what happens if suddenly implementation of getNameOfBrother method starts throwing NullPointerException for some random reason. Ask yourself - does your unit test protects you from such situation? Nope. Your test always passes, because you are stubbing the method you are testing. If you test a real implementation instead and you pass a real Person object then you will get notified about NullPointerException in the test. Otherwise you will see it when you deploy your code and some user's action calls this method and it fails.