Controller Test1使用TDD开发SpringBoot应用开发实践闲话编程Contents创建Integration Test ................................................................................. 1Controller Test ........................................................................................ 1Service ................................................................................................. 3Repository ............................................................................................. 3虽然觉得没什么卵用,但实际工作中还是必须要使用,这不最近就做了一个使用的方式开发的例子。下面阐述一下如何开发一个的请求,从数据库中读取数据并返回。创建Integration Test第一步可以从开始,即模拟真实发送一个请求,然后检验返回的。简单起见,第一步只校验状态值:@RunWith(SpringRunner.class)@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)public class IntegrationTest { @Autowired private TestRestTemplate testClient; @Test public void should_get_computer_list_when_call_list_computer_api() { ResponseEntity<List<ComputerDto>> response = testClient.exchange( "/computers", HttpMethod.GET, null, new ParameterizedTypeReference<List<ComputerDto>>() { }); assertEquals(HttpStatus.OK, response.getStatusCode()); }}这里特意使用以使得启动一个接近真实的,来测试我们的请求。当然这个测试会挂了,因为都还没写呢。所以下一个先来创建,但是呢,通常从测试开始写起,所以来测试吧。Controller Test测试就是单元测试了,不需要测试其他的组件(比如什么的。@RunWith(SpringRunner.class)@WebMvcTest(controllers = ComputerController.class)public class ComputerControllerTest { @Autowired Controller Test2 private MockMvc mockMvc; @Test public void should_get_a_list_when_get_computers() throws Exception { mockMvc.perform(MockMvcRequestBuilders.get("/computers")) .andExpect(status().isOk()); }}然后就是需要创建一个,让测试可以过:@RestController("/computers")public class ComputerController { @GetMapping public List<ComputerDto> getComputers() { return null; }}到这里基本上集成测试也可以过了。所以你可以先一次了。然后,当然我们不能把逻辑放到里面啊,我们需要一个来处理业务逻辑。这个又会从数据库中读取数据。在用到之前,我们可能需要先改一下我们的测试,因为到目前为止并没有校验实际的字段,只是校验了返回状态码,现在可以开始校验了: @MockBean private ComputerService computerService; @Test public void should_get_a_list_when_get_computers() throws Exception { given(computerService.getComputers()) .willReturn( Collections.singletonList( new ComputerDto(1, "MacBook 2015", "Haifeng Li", "2019-09-10") )); mockMvc.perform(MockMvcRequestBuilders.get("/computers")) .andExpect(status().isOk()) .andExpect(jsonPath("$", hasSize(1))) .andExpect(jsonPath("$[0].id").value(1)) .andExpect(jsonPath("$[0].type").value("MacBook 2015")) .andExpect(jsonPath("$[0].owner").value("Haifeng Li")) .andExpect(jsonPath("$[0].createTime").value("2019-09-10")) .andDo(print()); }这里我们把给掉,因此可以控制它的行为,实际的就一个空函数就可以了。 Repository3Service这时候,可以考虑实现了,因为需要读取数据库,所以需要引入一个来查询数据库,我们可以掉,来测的逻辑:@RunWith(MockitoJUnitRunner.class)public class ComputerServiceTest { @Mock private ComputerRepository computerRepository; @InjectMocks private ComputerService computerService; @Test public void should_return_computer_list_when_get_all_computers() throws ParseException { ComputerEntity stored = new ComputerEntity(1, "MacBook 2015", "Haifeng Li", new SimpleDateFormat("dd/MM/yyyy").parse("01/09/2019")); given(computerRepository.findAll()).willReturn(Collections.singletonList(stored)); List<ComputerDto> computers = computerService.getComputers(); assertEquals(1, computers.size()); assertEquals(1, computers.get(0).getId()); assertEquals("MacBook 2015", computers.get(0).getType()); assertEquals("Haifeng Li", computers.get(0).getOwner()); assertEquals("2019-09-01", computers.get(0).getCreateTime()); }}同样里面也就一个空函数就行了,但是这时候得把的逻辑写完,让测试可以通过,这样的任务就完成了,其他测试也全部都可以通过。Repository最后一步就是来实现了,这里需要使用,用内存数据库进行测试:@RunWith(SpringRunner.class)@DataJpaTestpublic class ComputerRepositoryTest { @Autowired private TestEntityManager entityManager; @Autowired private ComputerRepository computerRepository; Repository4 @Before public void prepareData() throws ParseException { entityManager.persistAndFlush(new ComputerEntity(1, "MacBook 2015", "Haifeng Li", new SimpleDateFormat("dd/MM/yyyy").parse("01/09/2019")) ); entityManager.persistAndFlush(new ComputerEntity(2, "Desktop", null, new SimpleDateFormat("dd/MM/yyyy").parse("02/09/2019")) ); } @Test public void should_return_all_records_in_db_when_find_all() { List<ComputerEntity> entities = computerRepository.findAll(); assertEquals(2, entities.size()); }}因为你只需要写一堆,测试这里的逻辑还是十分有必要的。所以到这一步为止,基本上程序的功能就已经实现了,唯一需要做的就是改一下配置来连接到真是的数据库。整个代码可以在我的上面找到。