java - Spock模拟调用模拟类的真实方法

标签 java spock

我有 Spock 集成测试来测试我的 Java 应用程序。对于其中一种方法,调用将转到真正的方法“bMethod()”,而不是返回 stub 值。它对于另一个方法“aMethd()”工作正常,并且返回 stub 值并且不调用实际方法。这两个方法都在同一个类 Calc 中。有没有办法调查 Spock 正在做什么以及为什么这样做?

public interface CalcIntf {
  public int aMethod(int a, int b);      
  public int bMethod(int a, int b, int c);
}

MyTestSpec extends Specification {
    def "aMethod test"() {
        given:
          ...
          CalcIntf calcIntf = Mock(CalcIntf)
          calcIntf.aMethod(_,_) >> { return 100; }
        when:
          //service call
        then:
          // asserts go here
    }

    def "bMethod test"() {
        given:
          ...
          CalcIntf calcIntf = Mock(CalcIntf)
          calcIntf.bMethod(_,_,_) >> { return 100; }
        when:
          // service call
        then:
          // asserts go here
    }
}

最佳答案

经过最少修复的原始代码

所以首先我让 m1m2 返回 int 而不是 void。那么至少你可以检查结果。然后我还确保这些方法在没有参数的情况下正确调用,正如克里斯已经提到的那样。所以现在的代码如下所示:

package de.scrum_master.stackoverflow.q62269054

import spock.lang.Specification

class MyTestSpec extends Specification {
  def "testing addition using aMethod"() {
    given:
    Math math = new Math()
    CalcIntf calcIntf = Mock(CalcIntf)
    calcIntf.aMethod(_, _) >> { return 123 }
    expect:
    math.m1() == 123
  }

  def "testing addition using bMethod"() {
    given:
    Math math = new Math()
    CalcIntf calcIntf = Mock(CalcIntf)
    calcIntf.bMethod(_, _, _) >> { return 456 }
    expect:
    math.m2() == 456
  }

  interface CalcIntf {
    int aMethod(int a, int b)

    int bMethod(int a, int b, int c)
  }

  static class Calc implements CalcIntf {
    int aMethod(int a, int b) {
      return a + b
    }

    int bMethod(int a, int b, int c) {
      return a + b + c
    }
  }

  static class Math {
    Calc calc = new Calc()

    int m1() {
      calc.aMethod(1, 2)
    }

    int m2() {
      calc.bMethod(1, 2, 3)
    }
  }
}

当然,测试失败了:

Condition not satisfied:

math.m1() == 123
|    |    |
|    3    false
...

Condition not satisfied:

math.m2() == 456
|    |    |
|    6    false
...

失败的原因是您没有在任何地方注入(inject)模拟,但是 Math 通过 Calc calc = new Calc 使用硬编码的 Calc 实例().

使测试通过

所以我们需要一种方法来注入(inject)模拟,例如通过构造函数或 setter 。您还应该将字段类型从 Calc 更改为 CalcIntf,否则无法注入(inject)接口(interface)模拟。如果您不在代码中使用接口(interface)而是针对具体子类进行编码,为什么还要创建接口(interface)?

package de.scrum_master.stackoverflow.q62269054

import spock.lang.Specification

class MyTestSpec extends Specification {
  def "testing addition using aMethod"() {
    given:
    CalcIntf calcIntf = Mock(CalcIntf)
    calcIntf.aMethod(_, _) >> { return 123 }
    Math math = new Math(calcIntf)
    expect:
    math.m1() == 123
  }

  def "testing addition using bMethod"() {
    given:
    CalcIntf calcIntf = Mock(CalcIntf)
    calcIntf.bMethod(_, _, _) >> { return 456 }
    Math math = new Math(calcIntf)
    expect:
    math.m2() == 456
  }

  interface CalcIntf {
    int aMethod(int a, int b)

    int bMethod(int a, int b, int c)
  }

  static class Calc implements CalcIntf {
    int aMethod(int a, int b) {
      return a + b
    }

    int bMethod(int a, int b, int c) {
      return a + b + c
    }
  }

  static class Math {
    CalcIntf calcIntf

    Math(CalcIntf calcIntf) {
      this.calcIntf = calcIntf
    }

    int m1() {
      calcIntf.aMethod(1, 2)
    }

    int m2() {
      calcIntf.bMethod(1, 2, 3)
    }
  }
}

您所描述的测试行为

现在测试通过了,但它们不会重现您所描述的行为:

For one of the methods, the call is going to the real method 'bMethod()', instead of the stubbed valued being returned.

我可以想象发生这种情况的一个原因:您想要 stub 的方法是final,这意味着实现模拟的动态代理无法覆盖它,因此不会 stub 它。但这与您在代码中描述的情况完全不同。

看到了吗?如果您的示例代码没有重现问题,那么它是完全无用的,这就是为什么在我的评论中我告诉您始终提供 MCVE 而不是一些随机伪代码。如果有人报告您的代码中存在错误,您还想知道如何重现它。

因此,为了重现您报告的问题,我必须做出有根据的猜测,因为您的代码没有帮助。只需在之前的版本中更改以下内容即可:

  • int bMethod(int a, int b, int c)final int bMethod(int a, int b, int c)
  • Mock(CalcIntf)Mock(Calc) 在 2 个位置

现在测试结果是:一种通过,一种失败的功能方法:

Condition not satisfied:

math.m2() == 456
|    |    |
|    6    false
...

关于java - Spock模拟调用模拟类的真实方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62269054/

相关文章:

spring - 如何在 Spock 测试中将 @Value 注释与 Spring PropertyPlaceholderConfigurer 一起使用?

grails - Grails 2.3.2/IntelliJ-GrailsUnitTestMixin中的NullPointerException shutdownApplicationContext

java - 如何将模拟对象注入(inject)到构造函数中?

java - 线程 "main"java.lang.UnsatisfiedLinkError 中的异常

selenium - 如何排除 Geb 中的测试?

c# - 使变量成为类的实例

java - 使进程等待

testing - Spock 和 Spock 报告 : how "catch" and customize the error message for AssertionError?

java - 保留拥有关系的实体,而不先获取关系的另一方

java - 如何在 java 中重绘打印控制台信息?