Jos*_*uss 10 java mockito spring-boot spring-boot-test
我正在开发一个 Spring Boot 应用程序。对于我的常规服务类单元测试,我可以使用 扩展我的测试类MockitoExtension,并且模拟很严格,这就是我想要的。
interface MyDependency {
Integer execute(String param);
}
class MyService {
@Autowired MyDependency myDependency;
Integer execute(String param) {
return myDependency.execute(param);
}
}
@ExtendWith(MockitoExtension.class)
class MyServiceTest {
@Mock
MyDependency myDependency;
@InjectMocks
MyService myService;
@Test
void execute() {
given(myDependency.execute("arg0")).willReturn(4);
myService.execute("arg1"); //will throw exception
}
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,将引发异常并显示以下消息(已编辑):
org.mockito.exceptions.misusing.PotentialStubbingProblem:
Strict stubbing argument mismatch. Please check:
- this invocation of 'execute' method:
myDependency.execute(arg1);
- has following stubbing(s) with different arguments:
1. myDependency.execute(arg0);
Run Code Online (Sandbox Code Playgroud)
此外,如果从未使用过存根,则会出现以下内容(已编辑):
org.mockito.exceptions.misusing.UnnecessaryStubbingException:
Unnecessary stubbings detected.
Clean & maintainable test code requires zero unnecessary code.
Following stubbings are unnecessary (click to navigate to relevant line of code):
1. -> at MyServiceTest.execute()
Run Code Online (Sandbox Code Playgroud)
但是,当我@MockBean在集成测试中使用时,不存在任何严格的行为。相反,存根方法会返回 null,因为存根会默默地“失败”。这是我不想要的行为。当使用意外的参数时,最好立即失败。
@SpringBootTest
class MyServiceTest {
@MockBean
MyDependency myDependency;
@Autowired
MyService myService;
@Test
void execute() {
given(myDependency.execute("arg0")).willReturn(4);
myService.execute("arg1"); //will return null
}
}
Run Code Online (Sandbox Code Playgroud)
有什么解决方法吗?
是的,有一些解决方法,但它非常复杂。最好等待 Mockito 4,其中默认为严格模拟。
第一个选项:
将 @MockBean 替换为 @Autowired,并使用 @Primary 进行测试配置(这应该具有与 @MockBean 相同的效果,将其插入到应用程序以及测试中)
创建一个默认答案,为任何未存根的函数抛出异常
然后用一些存根覆盖这个答案 - 但你必须使用 doReturn 而不是 thenReturn
// this is the component to mock
@Component
class ExtService {
int f1(String a) {
return 777;
}
}
// this is the test class
@SpringBootTest
@RunWith(SpringRunner.class)
public class ApplicationTests {
static class RuntimeExceptionAnswer implements Answer<Object> {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
throw new RuntimeException(
invocation.getMethod().getName() + " was not stubbed with the received arguments");
}
}
@TestConfiguration
public static class TestConfig {
@Bean
@Primary
public ExtService mockExtService() {
ExtService std = Mockito.mock(ExtService.class, new RuntimeExceptionAnswer());
return std;
}
}
// @MockBean ExtService extService;
@Autowired
ExtService extService; // replace mockBean
@Test
public void contextLoads() {
Mockito.doReturn(1).when(extService).f1("abc"); // stubbing has to be in this format
System.out.println(extService.f1("abc")); // returns 1
System.out.println(extService.f1("abcd")); // throws exception
}
}
Run Code Online (Sandbox Code Playgroud)
另一种可能但远非理想的选择:不使用默认答案,而是首先使用 any() 匹配器对所有函数调用进行存根,然后使用您实际期望的值。
这会起作用,因为存根顺序很重要,最后一场比赛获胜。
但同样:您将必须使用 doXXX() 系列存根调用,更糟糕的是,您将必须存根每个可能的函数以接近严格的模拟。
// this is the service we want to test
@Component
class ExtService {
int f1(String a) {
return 777;
}
}
// this is the test class
@SpringBootTest
@RunWith(SpringRunner.class)
public class ApplicationTests {
@MockBean ExtService extService;
@Test
public void contextLoads() {
Mockito.doThrow(new RuntimeException("unstubbed call")).when(extService).f1(Mockito.any()); // stubbing has to be in this format
Mockito.doReturn(1).when(extService).f1("abc"); // stubbing has to be in this format
System.out.println(extService.f1("abc")); // returns 1
System.out.println(extService.f1("abcd")); // throws exception
}
}
Run Code Online (Sandbox Code Playgroud)
另一种选择是等到使用模拟测试完成后,然后使用
verifyNoMoreInteractions();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1643 次 |
| 最近记录: |