我正在用JUnit 4和Mockito4.6.1编写一个单元测试。我在模拟一个具有特定输入值的接口方法。当传递不同的值时,我预期会出现参数不匹配错误,但不会抛出。
请考虑以下示例:
public class SomeTest {
@Test
public void test() {
SomeInterface mock = Mockito.mock(SomeInterface.class, Mockito.withSettings().strictness(Strictness.STRICT_STUBS));
// Only mock test(true) and not test(false).
Mockito.when(mock.test(true)).thenReturn(1);
Assert.assertEquals(mock.test(true), 1);
Assert.assertEquals(
// Expecting argument mismatch error
mock.test(false),
2
);
}
interface SomeInterface {
int test(Boolean arg);
}
}
我在嘲笑SomeInterface.test(true)
返回1,这和预期的一样。现在,当我调用mock.test(false)
时,我期望参数不匹配,因为它不是在模拟设置中定义的,并且启用了严格模式。相反,它返回0,就好像它被模仿了一样。
我是不是漏掉了导致这一切发生的东西?
发布于 2022-06-05 01:16:15
问题1.我们必须启用存根进行测试。
STRICT_STUBS -确保干净的测试,减少测试代码的重复,提高调试能力。灵活性和生产力的最佳结合。强烈推荐。计划默认为Mockito v4。通过MockitoRule、MockitoJUnitRunner或MockitoSession启用它。详细信息请参见STRICT_STUBS。
根据文档,它可以通过MockitoJUnitRunner.StrictStubs.class完成
@RunWith(MockitoJUnitRunner.StrictStubs.class)
@Rule public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
问题2.当模拟定义和模拟调用在一个源类中执行时,参数严格性不起作用。
根据Mockito 源代码
如果固执和调用位于同一个源文件中,我们假设它们在测试代码中,并且我们不会将其标记为不匹配:
摘要。工作测试将是:
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.quality.Strictness;
import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.StrictStubs.class)
public class SomeTest {
@Test
public void test() {
SomeInterface mock = Mockito.mock(SomeInterface.class, withSettings().strictness(Strictness.STRICT_STUBS));
Mockito.when(mock.test(true)).thenReturn(1);
SomeInterfaceImpl someInterface = new SomeInterfaceImpl(mock);
Assert.assertEquals(someInterface.test(), 2);
}
}
public interface SomeInterface {
int test(Boolean arg);
}
public class SomeInterfaceImpl {
private SomeInterface someInterface;
public SomeInterfaceImpl(SomeInterface someInterface) {
this.someInterface = someInterface;
}
public int test() {
return someInterface.test(false);
}
}
在执行死刑时我们得到:
org.mockito.exceptions.misusing.PotentialStubbingProblem:
Strict stubbing argument mismatch. Please check:
- this invocation of 'test' method:
someInterface.test(false);
-> at com.example.SomeInterfaceImpl.test(SomeInterfaceImpl.java:10)
- has following stubbing(s) with different arguments:
1. someInterface.test(true);
-> at com.example.SomeTest.test(SomeTest.java:26)
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.
更可取的解决方案
您可以使用IllegalArgumentException
为模拟定义默认答案,以防使用不匹配参数执行模拟。此解决方案将始终在没有源文件限制的情况下工作。
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import static org.mockito.Mockito.doReturn;
@RunWith(MockitoJUnitRunner.class)
public class SomeTest {
@Test
public void test() {
SomeInterface mock = Mockito.mock(SomeInterface.class, Mockito.withSettings().defaultAnswer(
invocation -> {
throw new IllegalArgumentException(String.format("You cannot invoke %s with %s", invocation.getMethod(), java.util.Arrays.toString(invocation.getArguments())));
}
));
// Only mock test(true) and not test(false).
doReturn(1).when(mock).test(true);
Assert.assertEquals(mock.test(true), 1);
Assert.assertEquals(
// Expecting argument mismatch error
mock.test(false),
2
);
}
}
在执行死刑时我们得到:
java.lang.IllegalArgumentException: You cannot invoke public abstract int com.example.SomeInterface.test(java.lang.Boolean) with [false]
https://stackoverflow.com/questions/72500235
复制相似问题