斯波克模拟称模拟类的真实方法



我有 Spock 集成测试来测试我的 Java 应用程序。对于其中一个方法,调用将转到真正的方法"bMethod((",而不是返回存根值。它适用于另一个方法'aMethd((',并且返回存根值并且不调用实际方法。这两种方法都属于同一类,Calc。有没有办法调查斯波克在做什么以及为什么?

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。那么至少你可以检查结果。然后,我还确保在没有参数的情况下正确调用这些方法,正如Chris已经提到的。所以现在的代码看起来像这样:

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
...

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

使测试通过

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

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)
}
}
}

您描述的测试行为

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

对于其中一个方法,调用将转到真正的方法"bMethod((",而不是返回存根值。

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

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

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

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

现在测试结果为:一个通过和一个不及格的特征方法:

Condition not satisfied:
math.m2() == 456
|    |    |
|    6    false
...

尝试类似

given: 'a math with a calculator that always returns 100'
def calc = Stub(CalcIntf) {
bMethod(_,_,_) >> 100
}
def math = new Math(calc)
when: 'the math is asked to calculate something'
def result = math.m2()
then: 'it returns 100'
result == 100

注意事项:

  • 推送到存根的返回值应该是返回的内容,而不是闭包

  • 您必须通过构造函数或其他方式在数学中设置存根计算

  • 你调用数学的方法不需要争论

最新更新