测试之MockMvc与Mockito

目录

MockMvc测试接口

测试类外壳

测试函数Controller内容编写

获取接口返回json

Mockito测试Service

thenReturn模拟结果

Throw模拟异常

Verify验证


MockMvc测试接口

测试类外壳

 @RunWith(SpringRunner.class)
 @SpringBootTest(classes = Application.class)
 @AutoConfigureMockMvc
 @Transactional
 @Sql(scripts = "/test.sql")
 ​
 public class ControllerTest {
 ​
     @Autowired
     MockMvc mockMvc;
     
     @Test
     public void test(){
         // do...
     }
     
 }

其中@Sql用法见测试之@Sql(自动插入sql脚本,测试后销毁)_夜落%的博客-优快云博客

测试函数Controller内容编写

mockmvc的perform方法内编写发送请求的url、编码、内容等信息,后面的.andExpect方法则是对获取返回信息的验证判断。

 // 测试 - 未使用查询时,获取到的数据量
 mockMvc.perform(post("/list/1/10"))
                 .andExpect(status().isOk())
                 .andExpect(jsonPath("$.code").value(200))
                 .andExpect(jsonPath("$.data.list").isNotEmpty())
                 .andExpect(jsonPath("$.data.list").isArray())
                 .andExpect(jsonPath("$.data.list", hasSize(3)));
                 
                 
 // 测试 - 使用查询时,查询用户12,获取到的数据
 SearchDTO search1 = SearchDTO.builder().id("12").build();
 mockMvc.perform(post("/list/1/10")
                 .contentType(MediaType.APPLICATION_JSON_UTF8)
                 .content(JSON.toJSONString(search1)))
                 .andExpect(status().isOk())
                 .andExpect(jsonPath("$.code").value(200))
                 .andExpect(jsonPath("$.data.list").isNotEmpty())
                 .andExpect(jsonPath("$.data.list").isArray())
                 .andExpect(jsonPath("$.data.list", hasSize(1)))
                 .andExpect(jsonPath("$.data.list[0].name").value("张三"));

获取接口返回json

 MvcResult mvcResult = mockMvc.perform(get("/list/1")).andReturn();
 MockHttpServletResponse response = mvcResult.getResponse();
 response.setCharacterEncoding("UTF-8");
 String JsonReturn = response.getContentAsString();

json转对象

 UserEntity userEntity = new ObjectMapper().readValue(JsonReturn,UserEntity.class);

json转List

 List<UserEntity> userList = new ObjectMapper().readValue(JsonReturn,
                               new TypeReference<List<UserEntity>>(){});

Mockito测试Service

Mockito可以模拟方法的返回结果。

例:Mockito.when(A).thenReturn(B); 即模拟A方法的返回结果为B。

thenReturn模拟结果

下面代码中,在UserDao上注解@MockBean表示Mockito会帮我们模拟出一个假的UserDao对象,该对象的方法返回结果由when()、thenReturn()模拟。

 @MockBean
 UserDao userDao;
 ​
 @Autowired
 UserService userService;
 ​
 @Test 
 public void test(){
 ​
     List<UserEntity> userList = new ArrayList<>();
     userList.add(new UserEntity().setId(1L).setUsername("小夜"));
     userList.add(new UserEntity().setId(2L).setUsername("小音"));
     Mockito.when(userDao.mySelectList(12)).thenReturn(userList);
 ​
     List<UserEntity> list = userService.mySelectList(12);
     list.forEach(System.out::println);
 ​
 }

其中:userService.mySelectList()方法使用了userDao.mySelectList()方法

 @Override
 public List<UserEntity> mySelectList(int id) {
     return userDao.mySelectList(id);
 }

结果:

 UserEntity(id=1, username=小夜, password=null, name=null)
 UserEntity(id=2, username=小音, password=null, name=null)

Throw模拟异常

此外,还可以使用thenThrow模拟出现异常

 Mockito.when(userDao.mySelectList(22)).thenThrow(new RuntimeException("不能输入22"));

也可以使用doThrow模拟异常,注意此时方法要写在when外面

 Mockito.doThrow(new RuntimeException("不能输入33")).when(userDao).mySelectList(33);

Verify验证

使用times(x)验证方法最大允许运行次数为x,超出则错误。

注意是“验证”,所以该方法的编写应该在测试语句的最后,即等业务方法执行完成后,检验其执行的次数。

 Mockito.verify(userDao,Mockito.times(2)).mySelectList(44);

其中times()可以换成atLeast()、atLeastOnce()、atMost()、atMoreOnce()以及never()。

方法字面意思即其含义,不再赘述。

结合使用Assert.that()等方法验证Service返回结果即可。

### MockMvcMockito 的适用场景及选择依据 #### 工具概述 MockMvcSpring 提供的一个专门用于测试 Web 层逻辑的工具,主要用于模拟 HTTP 请求并验证控制器的行为[^1]。而 Mockito 则是一个通用的 Java 模拟库,适用于任何需要隔离依赖项的单元测试场景[^3]。 --- #### MockMvc 的适用场景 MockMvc 主要针对的是 **Web 层的功能测试** 或者说是 **集成测试的一部分**。它允许开发者发送虚拟的 HTTP 请求到应用的 Controller 中,并验证返回的响应数据、状态码以及视图名称等内容。以下是它的典型应用场景: - 验证控制器方法是否正确处理了传入参数。 - 测试 RESTful API 是否按照预期返回 JSON 数据。 - 确认页面跳转或重定向是否按需发生。 - 对于复杂的业务流程,可以通过组合多个请求来模拟完整的交互过程。 示例代码如下: ```java import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; this.mockMvc.perform(get("/users/{id}", 1)) .andExpect(status().isOk()) .andExpect(content().string(containsString("John Doe"))); ``` 上述例子展示了如何利用 MockMvc 来发起 GET 请求并对结果进行断言操作。 --- #### Mockito 的适用场景 Mockito 更加专注于 **单元测试中的依赖关系管理**。当某个类的方法调用了外部服务或其他组件时,如果这些外部因素难以控制或者速度较慢,则可以借助 Mockito 创建假象(mock),从而使得被测函数独立运行而不受外界干扰。具体来说,适合以下情况: - 单元测试中屏蔽掉数据库访问部分。 - 替代第三方接口调用以便快速完成本地开发工作流。 - 当前正在调试的目标对象内部存在复杂计算链路但又不想实际执行它们的时候。 下面是一段关于使用 Mockito 设置行为的例子: ```java @Service public class UserService { private final UserRepository userRepository; public UserService(UserRepository userRepository) { this.userRepository = userRepository; } public String findUserNameById(int id){ Optional<User> userOptional = userRepository.findById(id); return userOptional.map(User::getName).orElse(null); } } @Test void testFindUserNameById() { // Arrange UserRepository mockRepo = Mockito.mock(UserRepository.class); User dummyUser = new User(); dummyUser.setId(101); dummyUser.setName("Alice"); when(mockRepo.findById(101)).thenReturn(Optional.of(dummyUser)); UserService serviceUnderTest = new UserService(mockRepo); // Act & Assert assertEquals("Alice", serviceUnderTest.findUserNameById(101)); } ``` 在此处我们创建了一个 `UserRepository` 的 mock 实例,并定义好特定输入下的输出规则,进而实现了对目标方法的有效检验。 --- #### 如何选择合适的工具? 选择哪种工具取决于具体的测试需求和技术背景: - 如果关注点在于应用程序对外暴露的服务端点表现形式及其关联逻辑准确性方面的话,那么应该优先考虑采用 **MockMvc** 进行相应的功能性验证活动; - 反之,在深入探讨单一模块内部运作机制期间遇到诸多间接影响因子的情况下,则推荐运用 **Mockito** 构建简洁明了而又高度可控的实验环境来进行细致剖析研究。 另外值得注意的一点就是两者并非完全对立的关系,很多时候还可以结合起来共同发挥作用——即先用 Mockito 处理那些不易操控的部分作为辅助手段之后再交给 MockMvc 去做最终的整体效果评估[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值