【问题标题】:Can Spock Mock a Java constructorSpock 可以模拟 Java 构造函数吗
【发布时间】:2014-01-17 19:44:19
【问题描述】:

试图扩大 Spock 在工作中的吸引力并遇到这个问题。实际上试图为 Groovy 类编写单元测试,但它调用了 Java。静态方法调用私有构造函数。代码如下:

private MyConfigurator(String zkConnectionString){
    solrZkClient = new SolrZkClient(zkConnectionString, 30000, 30000,
            new OnReconnect() {
                @Override
                public void command() { . . . }
            });
}

“SolrZkClient”来自第三方 (Apache) Java 库。由于它试图连接到 ZooKeeper,我想为这个单元测试模拟它(而不是在内部运行一个作为单元测试的一部分)。

我的测试毫无困难地到达了构造函数,但我无法通过那个 ctor:

def 'my test'() {
    when:
        MyConfigurator.staticMethodName('hostName:2181')
    then:
        // assertions
}

有没有办法做到这一点?

【问题讨论】:

    标签: java unit-testing groovy spock


    【解决方案1】:

    由于被测类是用 Groovy 编写的,因此您应该能够通过全局 Groovy Mock/Stub/Spy 模拟构造函数调用(参见 Spock Reference Documentation 中的 Mocking Constructors)。但是,更好的解决方案是将MyConfigurator 类的实现解耦,以使其更具可测试性。例如,您可以添加第二个构造函数和/或静态方法,允许传递SolrZkClient 的实例(或基接口,如果有的话)。然后你就可以轻松地传入一个 mock。

    【讨论】:

    • 谢谢彼得,这似乎是非常“常识”的建议。由于将其付诸实践而推迟接受此答案是有问题的。即使是少量代码的检查也能说明原因。该类的目的是成为隐藏 SolrCloud 配置的底层细节的抽象。为了“抽象”这些细节,我只需要一个connectString。因此,传入类试图隐藏的对象并不是一个真正的选择。今天会花更多时间在这上面,我会再次发表评论。
    • 为什么不能添加第二个构造函数?
    • 这会破坏封装——该类的目的之一是隐藏 SolrZkClient 的构造,而不是将其传递给调用链。
    • 您可以将构造函数封装为私有,并添加注释(或@OnlyForTesting 注释)。稍微开放一个类以获得更好的可测试性是很常见的。
    【解决方案2】:

    您可以使用 GroovySpy 在 Spock 中模拟构造函数

    例如:

    def 'my test'() {
     given: 
     def solrZkClient = GroovySpy(SolrZkClient.class,global: true);
     when:
        MyConfigurator.staticMethodName('hostName:2181')
     then:
        // assertions
    }
    

    【讨论】:

    • 该问题要求构造函数模拟。这是在模拟一个静态方法
    【解决方案3】:
    def anySubscriber = GroovySpy(RealSubscriber, global: true)
    
    1 * new RealSubscriber("Fred")
    

    将其放入 def setup(){ } 块或 given: 标签块内

    【讨论】:

      猜你喜欢
      • 2012-04-14
      • 2011-02-11
      • 1970-01-01
      • 1970-01-01
      • 2020-12-27
      • 2015-03-20
      • 1970-01-01
      • 2011-12-30
      相关资源
      最近更新 更多