TDD In SpringBoot
参考资料:
- 文章讲解TDD
- 视频讲解TDD
- 测试驱动开发在项目中的实践
- TDD的概述
代码示例说明
这里我根据github的代码,进行简要的说明和讲解,最后我们会自己来写一遍测试。
从接口层开始编写测试,从上至下,从接口到数据访问的顺序编写测试Controller层测试
@WebMvcTest(controllers = PokemonController.class) @AutoConfigureMockMvc(addFilters = false) @ExtendWith(MockitoExtension.class) public class PokemonControllerTests { @Autowired private MockMvc mockMvc; @MockBean private PokemonService pokemonService; @Autowired private ObjectMapper objectMapper; }
- mockMvc:用来模拟HTTP请求
- objectMapper:将对象转为JSON字符串
- pokemonService:PokemonController所依赖的Service对象,这里我们为了隔离外界的影响,将依赖的Service进行mock化,所以加上注解:
MockBean
,那这个对象的所有方法调用,就可以我们来控制执行。@Mock 和 @MockBean 的区别?
@Mock:
- @Mock 是 Mockito 库提供的注解,它允许你在测试类中声明一个mock对象。
- 使用 @Mock 注解的字段将在初始化测试类时被自动替换为mock对象,但这需要配合特定的运行器(如MockitoJUnitRunner.class)或手动调用 MockitoAnnotations.openMocks(this) 来初始化这些mock对象。
- @Mock 创建的mock对象并不会自动添加到Spring应用上下文(ApplicationContext)中。
@MockBean:
- @MockBean 是 Spring Boot Test 框架提供的注解,它同样可以创建mock对象,但它是在Spring Boot集成测试环境下使用的。
- 当你在一个使用了 @SpringBootTest 的测试类中使用 @MockBean 时,它不仅会创建指定类型的mock对象,而且会将这个mock对象作为bean注入到当前的Spring应用上下文中。
- 这意味着所有通过Spring容器依赖注入的方式来获取这个bean的地方,在测试期间都会得到这个mock对象,而不是实际的实现类。
从测试的角度就能看到,如果一个Controller依赖大量的Service对象,就需要进行大量的MockBean。测试的复杂性也就不断上升
单元测试这里遵守一种默认的规则(AAA模式):
- Arrange:做一些准备工作,比如新建对象,模拟对象行为
- Act:进行我们要执行的操作
- Assert:断言,看返回结果是否符合我们的预期
我们看一个示例:
@Test
public void PokemonController_CreatePokemon_ReturnCreated() throws Exception {
given(pokemonService.createPokemon(ArgumentMatchers.any())).willAnswer((invocation -> invocation.getArgument(0)));
ResultActions response = mockMvc.perform(post("/api/pokemon/create")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(pokemonDto)));
response.andExpect(MockMvcResultMatchers.status().isCreated())
.andExpect(MockMvcResultMatchers.jsonPath("$.name", CoreMatchers.is(pokemonDto.getName())))
.andExpect(MockMvcResultMatchers.jsonPath("$.type", CoreMatchers.is(pokemonDto.getType())));
}