赞
踩
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- </dependency>
- <!-- 不需要额外单独引入 不是Springboot项目需要引入以下依赖>
- <dependency>
- <groupId>org.mockito</groupId>
- <artifactId>mockito-core</artifactId>
- <version>4.0.0</version>
- <scope>compile</scope>
- </dependency>
- <dependency>
- <groupId>org.mockito</groupId>
- <artifactId>mockito-junit-jupiter</artifactId>
- <version>4.0.0</version>
- <scope>compile</scope>
- </dependency>
- /**
- * 使用junit5 创建Mockito 单元测试的第一种方式
- */
- @ExtendWith(MockitoExtension.class)
- class SecurityApplicationTests {
-
- @Mock
- private UserServiceImpl userService;
- }
- class SecurityApplicationTests {
-
- private UserServiceImpl userService;
-
- @BeforeEach
- public void init() {
- userService = Mockito.mock(UserServiceImpl.class);
- }
- }
- class SecurityApplicationTests {
-
- @Mock
- private UserServiceImpl userService;
-
- @BeforeEach
- public void init() {
- MockitoAnnotations.openMocks(this);
- }
- }
Mock对象 | 方法插桩 | 方法不插桩 | 作用对象 | 最佳实践 |
Mock对象 | 执行插桩逻辑 | 返回Mock的默认值 | 类,接口 | 被测试类或其依赖 |
Spy 对象 | 执行插桩逻辑 | 调用真实的方法 | 类,接口 | 被测试类 |
1.创建一个Mock对象 mockList,给List 集合的index 为0 下标位置插桩,然后使用断言去判断
需要注意的是:doReturn("World").when(mockList).get(0) 方法执行的对象可以是mock或者spy对象,而when(mockList.get(0)).thenReturn("Hello") 只能执行mock对象
- @ExtendWith(MockitoExtension.class)
- class SecurityApplicationTests {
-
- @Mock
- private List<String> mockList;
-
- @Test
- public void test1() {
- //插桩
- doReturn("World").when(mockList).get(0);
- when(mockList.get(0)).thenReturn("Hello");
- // 使用断言验证
- Assertions.assertEquals("Hello", mockList.get(0));
- }
- }
- @ExtendWith(MockitoExtension.class)
- class SecurityApplicationTests {
-
- @Mock
- private List<String> mockList;
-
- @Test
- public void test1() {
- // 返回值是void时使用的插桩方式
- doNothing().when(mockList).clear();
- mockList.clear();
- // 由于没有返回值,无法用断言判断,可以使用verify的方式去看执行的次数
- verify(mockList, times(1)).clear();
- }
- }
- @ExtendWith(MockitoExtension.class)
- class SecurityApplicationTests {
-
- @Mock
- private List<String> mockList;
-
- @Test
- public void test4() {
- // 插桩mockList 执行get方法时抛出异常
- doThrow(new RuntimeException()).when(mockList).get(anyInt());
- try {
- mockList.get(4);
- //如果没有抛出异常,则测试失败
- Assertions.fail("Should have thrown an exception");
- }catch (Exception e){
- Assertions.assertTrue(e instanceof RuntimeException);
- }
- }
- }
- @ExtendWith(MockitoExtension.class)
- class SecurityApplicationTests {
-
- @Mock
- private List<String> mockList;
-
- @Test
- public void test4() {
- //第一次调用返回hello, 第二次返回world, 第三次即以后都返回java
- when(mockList.get(0)).thenReturn("hello")
- .thenReturn("world")
- .thenReturn("java");
- Assertions.assertEquals("hello", mockList.get(0));
- Assertions.assertEquals("world", mockList.get(0));
- Assertions.assertEquals("java", mockList.get(0));
- }
- }
作用:若@InjectMocks 声明的变量需要用到mock/spy的对象mockito会自动使用当前类里的mock或spy对象进行按类型或名字的注入
注意事项:被@InjectMocks注解标注的属性必须是实现类,因为mockito会创建对应的实例对象,默认创建的对象未经过mockito的处理,因此配合@spy 注解使其变为mock 对象调用真实的方法
1.有如下代码,
- @Service
- public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService{
-
- @Resource
- private UserMapper userMapper;
-
-
- @Cacheable(value = "user", key = "#root.method.name + #username")
- public User getUserByUserName(String username) {
- QueryWrapper queryWrapper = new QueryWrapper();
- queryWrapper.eq("user_name", username);
- return userMapper.selectOne(queryWrapper);
- }
-
- }
2.选择类名,按Alt + Enter 键创建测试类,勾选Member 创建以图中命名的测试方法
3. 编写测试逻辑
- @ExtendWith(MockitoExtension.class)
- class UserServiceImplTest {
-
- @Spy
- @InjectMocks
- UserServiceImpl userService;
-
- @Mock
- UserMapper userMapper;
-
- @Test
- void getBaseMapper() {
- String username = "testuser";
- User expectedUser = new User();
- expectedUser.setId(1L);
- expectedUser.setUserName(username);
-
- when(userMapper.selectOne(any(QueryWrapper.class))).thenReturn(expectedUser);
-
- User actualUser = userService.getUserByUserName(username);
-
- assertEquals(expectedUser, actualUser);
- }
- }
4.运行测试类,下图种显示代码测试覆盖率
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。