我有一个方法,其中生成一个标识符,将其发送到某个外部依赖项并返回。我希望有一个单元测试,测试是否返回了发送到那里的相同值。
假设测试和代码如下所示:
def "test"() {
given:
def testMock = Mock(TestMock)
and:
def x
when:
def testClass = new TestClass()
x = testClass.callMethod(testMock)
then:
1 * testMock.method(x)
}
static interface TestMock {
void method(double x)
}
static class TestClass {
double callMethod(TestMock mock) {
double x = Math.random()
mock.method(x)
return x
}
}
代码工作正常,但测试失败,并显示一条消息:
One or more arguments(s) didn't match:
0: argument == expected
| | |
| | null
| false
0.5757686318956925
因此,看起来then
中的模拟检查是在when
块中赋值之前完成的。
有没有办法让Spock在检查模拟调用之前分配这个值?或者我可以用不同的方法来做这个检查吗?
我唯一的想法是向方法(或者实际上是类)注入一个id生成器,并在测试中将其存根,但这会使代码复杂化,我希望避免这样做。
我根据kriegaex注解修复了代码示例。
1条答案
按热度按时间oknrviil1#
修复示例代码
在我们开始之前,您的示例代码有两个问题:
1 * testMock(x)
应该是1 * testMock.method(x)
callMethod
应返回double
,而不是int
,因为否则结果将始终为0(0和1之间的双精度浮点数在转换为整数时将始终生成0)。下次请确保您的示例代码不仅能编译,而且能完成预期的任务。示例代码只有在没有额外bug的情况下才有帮助,帮助您的人需要先修复这些bug,然后才能专注于实际问题。
眼前的问题
正如您已经注意到的,交互即使是在
then:
块中按词法定义的,也会通过Spock的编译器AST转换进行转换,当mock被初始化时,它们被注册在mock上。这是必要的,因为在调用when:
块中的任何方法之前,mock必须准备好。在已经执行了when:
块的情况下,试图直接使用一个以后才知道的结果,将导致您描述的问题。* 先有鸡还是先有蛋?* 在这种情况下,您不能指定方法参数约束,使用另一个方法调用约束中的mock方法的未来结果。解决方法
一种可能的解决方法是将方法存根化,并捕获闭包中的参数来计算存根结果,例如
>> { args -> arg = args[0]; return "stubbed" }
。当然,在Groovy中闭包或方法的最后一条语句中,return
关键字是多余的。在您的示例中,方法甚至是void
,因此在这种情况下您根本不需要返回任何内容。示例
我修改了您的示例代码,重命名了类、方法和变量,以便更清楚地描述哪些是什么以及正在发生什么:
第一个
请在Groovy Web Console中尝试。