【问题标题】:Don't understand how interactions really work in Spock不明白交互在 Spock 中是如何工作的
【发布时间】:2015-07-31 13:17:57
【问题描述】:

这是一个在 Groovy 中超级简单的 spock 测试用例。!!本规范文件中定义的所有类/接口。 (spock 中的规范文件只是一个测试用例文件)。

似乎无法理解工作流程。在测试用例工作流程中,模拟对象是如何被实例化、注入和销毁的?任何帮助表示赞赏...

我遇到的特殊问题是理解交互语句:1*mockURLAdapter.openConnection() 的工作原理。在我的理解中,这只是一个验证语句,断言使用非空参数调用方法“openConnection(_)”。调用此断言如何/为什么会导致方法 weatherService.run() 失败?返回的异常见代码...

import spock.lang.Specification

class WeatherServiceImpl {
    private URLAdapter urlAdapter;
    private URLConnection urlConn;

    public WeatherServiceImpl(urlAdapter){
        this.urlAdapter=urlAdapter
    }

    def run(city) {
        urlConn=urlAdapter.openConnection(city)
        return urlConn.getResponseCode()

    }

}

interface URLAdapter {
    def openConnection(city)

}


class WeatherServiceImplSpec extends Specification {

    def mockURLAdapter = Mock(URLAdapter)
    def mockURLConn    = Mock(HttpURLConnection)
    def weatherService=new WeatherServiceImpl(mockURLAdapter);


    def "Need to figure out the effects of lines: 'troublesome' and 'weirdo' "() {
        given:
        mockURLConn.getResponseCode()>> 9999
        mockURLAdapter.openConnection(_)>>mockURLConn;

        when:
        def result=weatherService.run("New York")

        then:
        // Uncommenting line 'troublesome' below throws a null-pointer exception:
        // java.lang.NullPointerException: Cannot invoke method getResponseCode() on null object
        //      at WeatherServiceImpl.run(URLAdapterConnectionSpec.groovy:29)
        //      at WeatherServiceImplSpec.delivers events to all subscribers(URLAdapterConnectionSpec.groovy:54)

        // Commenting out line 'troublesome' gives no issue!!

        // Line 'troublesome':
        // 1*mockURLAdapter.openConnection(_)

        // Line 'weirdo':
        // And yet, line 'weirdo' works just fine, commented or not!(i.e. test passes, no exception thrown)!!
        1*mockURLAdapter.openConnection(_)>>mockURLConn;

        //WTH is happening! ?
        result==9999


    }

}

【问题讨论】:

  • 相信你已经看过fine manual了。
  • 一遍又一遍..迷失在细节中!
  • 我不明白你的疑问......当你需要存根时,你再次使用模拟。
  • 据我了解,mock 允许从 stub 等所有内容。虽然模拟对象允许存根方法调用,但它们也允许交互验证.. 即 1*mockURLAdapter.open...、1*mockURLConnection.getResponseCode( ) 等。是的,对于这个例子,存根就足够了。但对于许多其他用途,模拟也可能是首选。

标签: unit-testing groovy mocking spock


【解决方案1】:

你指定了两次 mockURLAdapter 应该返回的内容,第二次你说不返回任何东西,当然这取决于你最后的决定。

// Line 'troublesome':
1 * mockURLAdapter.openConnection(_)

这意味着当调用 openConnection(_) 时不会返回任何内容。如果你想指定交互,那么你应该把它放在 then: 子句中

正确的做法应该是这样的:

def "Need to figure out the effects of lines: 'troublesome' and 'weirdo' "() {
        when:
        def result=weatherService.run("New York")

        then:
        1 * mockURLAdapter.openConnection(_) >> mockURLConn;
        1 * mockURLConn.getResponseCode() >> 9999

        result == 9999
}

【讨论】:

  • 嗯..谢谢!我工作中的一些同事最终也发现了这一点。确实和Mockito的做事方式不同。事实上,很长一段时间以来,我一直在努力理解耦合方法与存根交互的设计(即为什么要这样?)。但我想,它最终允许更灵活的模拟和存根。 IE。第一次,返回一些东西,然后在第二次调用中,返回一些东西......毕竟可能会更好。
猜你喜欢
  • 1970-01-01
  • 2014-07-15
  • 2021-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多