对于 Mockito 中的每个 `when` 调用,最好有一个 `verify` 调用吗?
Is it preferred to have a `verify` call for each `when` call in Mockito?
编写测试用例时,通常的模式是 setup
> execute
> verify
。这导致单元测试看起来像这样:
@Test
void testSomething() {
// Setup
when(someMock.someMethod()).thenReturn("someValue");
// Execute (the doSomething implementation would invoke someMock.someMethod)
testee.doSomething();
// Verify
verify(someMock, times(1)).someMethod();
}
我的问题是,考虑到 call
何时会引发 UnnecessaryStubbingException
异常,是否有必要包含 verify
调用?
此问题仅适用于 times
为 1
的情况,因为缺少 UnnecessaryStubbingException
仅意味着 someMethod
已被调用一次并使用正确的参数和在某些情况下,您可能想要验证 someMethod
是否已被调用 never
。如果没有验证,测试将如下所示并实现相同的检查:
@Test
void testSomething() {
// Setup
when(someMock.someMethod()).thenReturn("someValue");
// Execute (the doSomething implementation would invoke someMock.someMethod)
testee.doSomething();
}
编辑:一位朋友指出 verifyNoMoreInteractions
依赖于您有 verify
个电话,所以我想考虑这一点很重要。
编辑 2:我已将标题中的“必要”更改为“首选”,因为我对每种方法的 pros/cons 与技术要求相比更感兴趣。
提前致谢!
如您所述,不需要 - 技术测试验证了此行为。因此,选择应该来自您团队的偏好和专业知识。我个人认为 具有明确的验证步骤 使您的测试更具可读性和可维护性。几个原因:
- 你可以有更多的
when
调用,与验证逻辑无关,这将“隐藏”测试意图,例如
@Test
void testSomething() {
// Setup
when(someMock.someMethod()).thenReturn("someValue");
when(someMock2.someMethod2()).thenReturn("someValue2");
when(someMock3.someMethod3()).thenReturn("someValue3");
// Execute (the doSomething implementation
// would invoke someMock.someMethod)
testee.doSomething();
// code reviewer - "hm? what do we really test here?"
}
- 从 API 的角度来看,在
UnnecessaryStubbingException
和 when
中抛出异常并不明显 - 这可能会给偶尔错过该事实的代码 reader 带来混乱。拥有 verify
让几乎所有开发人员都清楚测试的意图,即使来自其他技术堆栈
- 一些开发人员可能来自早期的 Mockito 版本,其中抛出
UnnecessaryStubbingException
不是这种情况
UnnecessaryStubbingException
仅在 Mockito 处于严格模式时才会引发。如果此设置更改为 lenient down the line,您将无法再依赖引发此异常。
- 您可以创建不包括
verify
调用意味着后续 verifyNoMoreInteractions
调用将失败的场景。
如果您已经知道您的代码片段会抛出异常,最好有一个测试用例来覆盖它,如下所示
@Test(预期=UnnecessaryStubbingException.class)
没有任何断言或验证语句的测试用例(您显示的跳过验证的那个)没有任何意义。当方法具有 void return 类型时,对情况进行验证检查是一种很好的方法。
不,在 Mockito 中调用时不需要为每个添加 Verify。每个测试用例本质上都应该是确定性的。
要回答您的问题,在这种特殊情况下,首选方法是使用 verifyNoMoreInteractions
或 verify(somemock, never()).someMethod()
您不必总是需要验证。您也可以使用 assertions。但是,一个测试用例必须有其中之一。
例如。如果您确定某些方法将抛出异常。
@Test(expected = HeyIAmException.class)
void testSomething() {
classUnderTest.someMethodWhichThrowsException();
}
或在 Junit 5 中。
@Test
void testSomething() {
when(someMock.someMethod()).thenReturn("someValue");
HeyIAmException exception = assertThrows(HeyIAmException.class, () ->
classUnderTest.someMethodWhichThrowsException()
);
assertEquals(exception.getCode(),rightCode);
}
在你的方法中,除了 Udalmik 的回答之外,我还添加了以下更多行。
- 我们永远不会知道哪个存根方法导致了异常,因为任何
someMethod
都可能抛出异常。
- 测试的意图不是很明确
编写测试用例时,通常的模式是 setup
> execute
> verify
。这导致单元测试看起来像这样:
@Test
void testSomething() {
// Setup
when(someMock.someMethod()).thenReturn("someValue");
// Execute (the doSomething implementation would invoke someMock.someMethod)
testee.doSomething();
// Verify
verify(someMock, times(1)).someMethod();
}
我的问题是,考虑到 call
何时会引发 UnnecessaryStubbingException
异常,是否有必要包含 verify
调用?
此问题仅适用于 times
为 1
的情况,因为缺少 UnnecessaryStubbingException
仅意味着 someMethod
已被调用一次并使用正确的参数和在某些情况下,您可能想要验证 someMethod
是否已被调用 never
。如果没有验证,测试将如下所示并实现相同的检查:
@Test
void testSomething() {
// Setup
when(someMock.someMethod()).thenReturn("someValue");
// Execute (the doSomething implementation would invoke someMock.someMethod)
testee.doSomething();
}
编辑:一位朋友指出 verifyNoMoreInteractions
依赖于您有 verify
个电话,所以我想考虑这一点很重要。
编辑 2:我已将标题中的“必要”更改为“首选”,因为我对每种方法的 pros/cons 与技术要求相比更感兴趣。
提前致谢!
如您所述,不需要 - 技术测试验证了此行为。因此,选择应该来自您团队的偏好和专业知识。我个人认为 具有明确的验证步骤 使您的测试更具可读性和可维护性。几个原因:
- 你可以有更多的
when
调用,与验证逻辑无关,这将“隐藏”测试意图,例如
@Test
void testSomething() {
// Setup
when(someMock.someMethod()).thenReturn("someValue");
when(someMock2.someMethod2()).thenReturn("someValue2");
when(someMock3.someMethod3()).thenReturn("someValue3");
// Execute (the doSomething implementation
// would invoke someMock.someMethod)
testee.doSomething();
// code reviewer - "hm? what do we really test here?"
}
- 从 API 的角度来看,在
UnnecessaryStubbingException
和when
中抛出异常并不明显 - 这可能会给偶尔错过该事实的代码 reader 带来混乱。拥有verify
让几乎所有开发人员都清楚测试的意图,即使来自其他技术堆栈 - 一些开发人员可能来自早期的 Mockito 版本,其中抛出
UnnecessaryStubbingException
不是这种情况 UnnecessaryStubbingException
仅在 Mockito 处于严格模式时才会引发。如果此设置更改为 lenient down the line,您将无法再依赖引发此异常。- 您可以创建不包括
verify
调用意味着后续verifyNoMoreInteractions
调用将失败的场景。
如果您已经知道您的代码片段会抛出异常,最好有一个测试用例来覆盖它,如下所示
@Test(预期=UnnecessaryStubbingException.class)
没有任何断言或验证语句的测试用例(您显示的跳过验证的那个)没有任何意义。当方法具有 void return 类型时,对情况进行验证检查是一种很好的方法。
不,在 Mockito 中调用时不需要为每个添加 Verify。每个测试用例本质上都应该是确定性的。
要回答您的问题,在这种特殊情况下,首选方法是使用 verifyNoMoreInteractions
或 verify(somemock, never()).someMethod()
您不必总是需要验证。您也可以使用 assertions。但是,一个测试用例必须有其中之一。
例如。如果您确定某些方法将抛出异常。
@Test(expected = HeyIAmException.class)
void testSomething() {
classUnderTest.someMethodWhichThrowsException();
}
或在 Junit 5 中。
@Test
void testSomething() {
when(someMock.someMethod()).thenReturn("someValue");
HeyIAmException exception = assertThrows(HeyIAmException.class, () ->
classUnderTest.someMethodWhichThrowsException()
);
assertEquals(exception.getCode(),rightCode);
}
在你的方法中,除了 Udalmik 的回答之外,我还添加了以下更多行。
- 我们永远不会知道哪个存根方法导致了异常,因为任何
someMethod
都可能抛出异常。 - 测试的意图不是很明确