模拟方法返回null值,当检查调用时。

7

我不确定是否在误用基于交互的测试或者是否存在概念上的错误。我正在开发一个Spring Boot 应用程序(使用Kotlin),我的测试使用Spock/Groovy。

我有一个被测试类,它调用另一个服务来查询信息。被测试类应该缓存结果。然而,我无法模拟带有返回值的方法并检查调用次数,因为一旦添加了对调用次数的检查,模拟方法就总是返回null。

我创建了一个隔离的示例,展示了这个问题。

这是被测试的类:

@Service
class DemoService(private val downstreamService: DownstreamService) {
    fun demo(id: String): String {
        val something = downstreamService.something(id)
        return something
    }
}

正在使用此服务的是:

@Service
class DownstreamService {
    fun something(id: String): String {
        return id
    }
}

这是我的测试样例:

class DemoServiceTest extends Specification {
    def downStream = Mock(DownstreamService)
    def demoService = new DemoService(downStream)

    def "value check"() {
        given:
        def test = "my test string"
        downStream.something(test) >> "xxx"

        when:
        def actual = demoService.demo(test)

        then:
        actual == "xxx" // works
    }   

    def "invocation check"() {
        given:
        def test = "my test string"
        downStream.something(test) >> "xxx"

        when:
        demoService.demo(test)

        then:
        1 * downStream.something(test) // works
    }

    def "combined check"() {
        given:
        def test = "my test string"
        downStream.something(test) >> "xxx"

        when:
        def demo = demoService.demo(test)

        then:
        1 * downStream.something(test)
        demo == "xxx" // fails because demo is null
    }

}

第一和第二个测试按预期工作,但最后一个测试失败了,因为当我添加调用检查时,返回值始终为null。

2
请参见http://spockframework.org/spock/docs/1.3/all_in_one.html#_combining_mocking_and_stubbing。 - Leonard Brünings
如果在该示例的顶部添加一个注释,例如 # This will not work,将有助于发现这些信息。上面句子中的“not”很容易被忽略... 段落结束... 在视觉上很难发现。谢谢。 - user1241663
2个回答

8

结合模拟和调用次数检查存在问题,因为如果没有调用到模拟对象,则不会被调用。

您可以使用以下方式重写组合测试以使其正常工作:

def "combined check"() {
    given:
    def test = 'my test string'

    when:
    def demo = demoService.demo(test)

    then:
    1 * downStream.something(test) >> 'xxx'
    demo == 'xxx'
}

这在Spring Webflux中效果不佳。我可以告诉我的模拟类返回一个Mono,但它总是返回null:如果在then块中使用1 * someService.getData(id) >> Mono.just(new Response()),它将始终返回null。使用Mockito似乎效果更好:( - jndietz

1
Spock将根据*或>>,>运算符解释交互。然后块中的交互优先于给定或when:块中的交互。
由于您的then块中的交互未指定响应,因此默认响应将为null。
交互和存根应该像答案中提到的那样一起使用。
您可以参考文档以获取详细说明 :)
  1. 声明交互的位置
  2. 组合Mocking和Stubbing

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接