【问题标题】:Mocked method returns null when invocations are checked as well在检查调用时,模拟方法也返回 null
【发布时间】:2019-04-30 07:58:12
【问题描述】:

我不确定我是否在滥用基于交互的测试,或者我是否在做一些概念上的错误。我正在开发一个 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。

【问题讨论】:

  • @LeonardBrünings 如果在该示例的顶部有注释,例如# This will not work,这将有助于发现信息,上面句子中的“不”很容易错过......段落结尾... 视觉上难以发现。谢谢。

标签: spring groovy kotlin spock


【解决方案1】:

将 mocking 与调用计数检查结合起来存在问题,因为那时没有调用 mock。

您可以通过这种方式重写您的组合测试以使其正常工作:

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 似乎效果更好:(
【解决方案2】:

Spock 将根据 * 或 >>、> 运算符解释交互。 并且 then 块中的交互将优先于给定或 when: 块中的交互。

由于 then 块中的交互未指定响应,因此默认响应将为 null。

answer 中所述,交互和存根应该结合在一起

详细解释可以参考文档:)

  1. Where to declare interactions
  2. Combining Mocking and Stubbing

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-30
    • 2018-04-27
    • 2020-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-15
    相关资源
    最近更新 更多