“调用次数太少”,但是调用了方法,并且使用GroovySpy或GroovyMock创建了所有内容

时间:2019-06-18 15:51:08

标签: java unit-testing mocking spock

我有这样的课:

class A(B b, C c, D d, E e) {

   protected void doSth() {
       test();
   }

   protected void test() {
      System.out.println("test");
   }
}

,我正在尝试测试是否调用了doSth()方法,然后还调用了test()方法。方法的返回类型为void,因此我无法测试这些方法的结果。

我的测试看起来像这样

    def "test when doSth"() {
        given: 'A class'
        A aClass = GroovySpy(A, constructorArgs: [GroovyMock(B), GroovyMock(C), GroovyMock(D), GroovyMock(E)) as A

        when:
        A.doSth()

        then:
        1 * A.test()
    }

,但此测试无效。它为测试方法提供了“调用次数太少”的错误。我真的很困惑,因为完全相同的示例但构造函数中没有args可以正常工作。

1 个答案:

答案 0 :(得分:0)

首先,我不知道您的Java类使用哪种语法。我猜它不是真的Java,但也许像Kotlin?我不知道,关于JVM语言,我只会讲Java和Groovy。因此,让我像这样重新创建您的测试对象:

package de.scrum_master.stackoverflow.q56652868;

public class A {
  private B b;
  private C c;
  private D d;
  private E e;

  public A(B b, C c, D d, E e) {
    this.b = b;
    this.c = c;
    this.d = d;
    this.e = e;
  }

  protected void doSth() {
    test();
  }

  protected void test() {
    System.out.println("test");
  }

  public static class B {}
  public static class C {}
  public static class D {}
  public static class E {}
}

我希望这可以。

对于您的测试,我不确定测试此交互(test()调用的方法doSth())对于您的应用程序是否确实必要,应该首先进行测试。我认为这种互动测试对于某些设计模式非常重要,例如您想检查是否当发生某些特定事件时,主题会通知某些注册观察员。测试类的内部连接,尤其是非公共方法,通常效果不佳,并且可能导致规范过度和脆弱的测试,如果不是类的公共API而是仅内部实现发生变化,则需要经常对其进行更新。 / p>

话虽如此,现在我还是出于教育目的回答您的问题。


您的测试中有几处错误:

  • 语法错误。您在定义Groovy间谍的行中缺少构造函数参数列表的结尾]
  • 这并不是一个错误,但是为什么要过多指定间谍的类型呢?而不是A aClass = GroovySpy(A, ...) as A可以确保它确实是A的3倍。为什么不只是A aClass = GroovySpy(...)还是def aClass = GroovySpy(A, ...)?无需也通过Aas A转换为自身。
  • 不要使用Groovy模拟和间谍,而是正常的Spock模拟和间谍。您不需要高级的Groovy模拟功能,此外,对于本身不在Groovy中实现的目标类,这些功能也无法正常工作,如Spock手册中所述。它们的行为就像普通的Spock模拟一样。
  • 最后但并非最不重要的一点是,真正的错误发生了:您编写A.doSth()A.test()就像处理静态方法一样。为什么?您需要编写aClass.doSth()aClass.test(),然后您的测试才能通过:
package de.scrum_master.stackoverflow.q56652868

import de.scrum_master.stackoverflow.q56652868.A.B
import de.scrum_master.stackoverflow.q56652868.A.C
import de.scrum_master.stackoverflow.q56652868.A.D
import de.scrum_master.stackoverflow.q56652868.A.E
import spock.lang.Specification

class ATest extends Specification {
  def "test when doSth"() {
    given: 'A class'
    A aClass = Spy(constructorArgs: [Mock(B), Mock(C), Mock(D), Mock(E)])

    when:
    aClass.doSth()

    then:
    1 * aClass.test()
  }
}
相关问题