我试着用Mockito模拟类的行为,这在Mockito 1.x中是有效的,但在迁移到JUnit 5和Mockito 2后似乎不再有效了。
@ExtendWith(MockitoExtension.class)
public class MockitoExample {
static abstract class TestClass {
public abstract int booleanMethod(boolean arg);
}
@Mock
TestClass testClass;
@BeforeEach
public void beforeEach() {
when(testClass.booleanMethod(eq(true))).thenReturn(1);
when(testClass.booleanMethod(eq(false))).thenReturn(2);
}
@Test
public void test() {
assertEquals(1,testClass.booleanMethod(true));
assertEquals(2,testClass.booleanMethod(false));
}
}
期望模拟的TestClass显示在test方法中测试的行为。
我得到的错误是:
org.mockito.exceptions.misusing.PotentialStubbingProblem:
Strict stubbing argument mismatch. Please check:
- this invocation of 'booleanMethod' method:
testClass.booleanMethod(false);
-> at org.oneandone.ejbcdiunit.mockito_example.MockitoExample.beforeEach(MockitoExample.java:30)
- has following stubbing(s) with different arguments:
1. testClass.booleanMethod(false);
-> at org.oneandone.ejbcdiunit.mockito_example.MockitoExample.beforeEach(MockitoExample.java:29)
Typically, stubbing argument mismatch indicates user mistake when writing tests.
Mockito fails early so that you can debug potential problem easily.
However, there are legit scenarios when this exception generates false negative signal:
- stubbing the same method multiple times using 'given().will()' or 'when().then()' API
Please use 'will().given()' or 'doReturn().when()' API for stubbing.
- stubbed method is intentionally invoked with different arguments by code under test
Please use default or 'silent' JUnit Rule (equivalent of Strictness.LENIENT).
For more information see javadoc for PotentialStubbingProblem class.
在这两种情况下,参数false
似乎是匹配的,尽管我清楚地匹配了true
。
这是Mockito 2.17中的一个bug还是一个误解。我应该/可以如何使用Mockito 2.x来模拟带有不同布尔参数的调用?
example也可以在github上找到,但是surefire只会使用
mvn test -Dtest=MockitoExample
使用Mockito 2.21执行测试会得到相同的结果。
5条答案
按热度按时间dfty9e191#
从Mockito 2.20开始,还可以在本地添加lenent()
bxgwgixi2#
使用strict stub(Mockito的默认行为)时,在同一个方法上调用多个
when
会重置模拟。解决方案是调用when
一次,并在Answer
中包含逻辑:或者,您可以使用宽松的模拟,但这并不总是一个好主意-宽松的模拟允许冗余的存根,并使您更容易在测试中出错,这可能会导致“生产”代码中未被注意到的bug:
webghufk3#
Mockito 1和2没有相同的"严格性"级别。
此外,通过使用Mockito 2和JUnit 4或5,默认级别仍然不同。
总结如下:
3个严格级别:
LENIENT
:最小严格度WARN
:向控制台发出额外警告STRICT_STUBS
:如果存在潜在误用,则通过抛出异常来确保干净的测试,但也可能产生一些假阳性。根据所用API的默认有效级别:
LENIENT
WARN
MockitoExtension.class
):STRICT_STUBS
STRICT_STUBS
。实际的Mockito文档对此非常清楚:
Strictness
javadoc声明:在模拟会话期间配置Mockito的"严格性"。一个会话通常Map到单个测试方法调用。严格性可以使测试更干净,生产率更高。利用增强的严格性的最简单方法是使用Mockito的JUnit支持(MockitoRule或MockitoJUnitRunner)。如果无法使用JUnit支持,则可以使用MockitoSession。
严格程度如何影响测试行为(模拟会话)?
Strictness.LENIENT
-没有附加的行为。Mockito 1.x的默认值。仅当您不能使用STRICT_STUBS或WARN时推荐使用。Strictness.WARN
-帮助保持测试干净并提高可调试性。报告有关未使用的存根和存根参数不匹配的控制台警告(请参阅org.mockito.quality.MockitoHint)。使用JUnitRule或MockitoJUnitRunner时Mockito 2.x的默认行为。如果无法使用STRICT_STUBS,建议使用此选项。Strictness.STRICT_STUBS
-确保干净的测试,减少测试代码重复,提高可调试性。灵活性和生产力的最佳组合。强烈推荐。计划作为Mockito v3的默认值。有关详细信息,请参阅STRICT_STUBS。但是无论抛出的异常与消息关联
"具有以下带有不同参数的存根"
似乎是一个过于严格的检查。异常消息在某种程度上证明了这一点:
但是,当此异常生成假阴性信号时,存在合法场景:
...
因此,默认禁止它似乎有点过分。
因此,如果您使用JUnit 5,作为
STRICT_STUBS
的替代方案,您可以使用WARNING
,但您通常希望避免使用过于安静的LENIENT
。除了
MockitoExtension
之外,mockito-junit-jupiter
库还提供了可以在方法级别和类级别使用的@MockitoSettings
。下面是一个例子:
foo()
成功时,fooKo()
抛出误用Mockito异常,但提供有用的警告:作为另一种选择,你也可以使用aschoerk很好地描述的
Mockito.lenient()
来为特定的调用应用宽松的严格性,你也可以在模拟示例化时将每个模拟调用设置为宽松的:ux6nzvsh4#
将@ExtendWith(MockitoExtension.class)替换为@ExtendWith(SpringExtension.class),如果您使用的是Spring,它解决了我的问题。
hwamh0ep5#
由于第一个答案出乎意料,我检查了以下内容:
它适用于Mockito 2.21.0。
更新:问题似乎出在Jupiter Mockito扩展上,它将默认设置更改为
Strictness.STRICT_STUBS
。