最近做了一些Spring Boot單元測試方面的東西,總結一下。
單元測試儘量要和Spring Boot框架減少耦合度,當你在測試某一項功能點是需要mock太多的對象時你就應該意識到這個功能點的耦合度太高了
使用Constructor Injection,不要使用Field Injection。這樣才能更容易寫單元測試代碼。在Spring Framework 4.3以後,如果你只有一個Constructor, 就不再需要寫@Autowired,Spring會默認他是autowire目標:
public class OrderEntryServiceImpl implements OrderEntryService { private OrderEntryRepository orderEntryRepository; public OrderEntryServiceImpl(OrderEntryRepository repository) { orderEntryRepository=repository; } }
這樣的話在單元測試中初始化對象就很容易
public class OrderEntryServiceTest { @MockBean private OrderEntryRepository orderEntryRepository; private OrderEntryService service; @Before public void setUp() { orderEntryRepository=Mockito.mock(OrderEntryRepository.class); service=new OrderEntryServiceImpl(orderEntryRepository); } private OrderEntry orderEntry=new OrderEntry(); @Test public void findByIdTest() { Mockito.when(orderEntryRepository.findOne(Mockito.anyLong())).thenReturn(orderEntry); OrderEntry entry=service.findById(new Long(1)); assertEquals(entry.getId(),orderEntry.getId()); } @Test public void updateEntryTest() throws Exception { final String orderEntryJson = IOUtils.toString(this.getClass().getResourceAsStream("/static/meta-data/orderentry-example.json"), CharEncoding.UTF_8 ); ObjectMapper mapper= ObjectMapperFactory.getInstance(); Mockito.when(orderEntryRepository.getOne(Mockito.anyLong())).thenReturn(orderEntry); Mockito.doAnswer(returnsFirstArg()).when(orderEntryRepository).save(Mockito.any(OrderEntry.class)); OrderEntry entry =service.update(new Long(1),mapper.readTree(orderJson)); assertEquals(new Long(2),entry.getQuantity()); assertEquals(new Double(10),entry.getUnitPrice()); } }
測試Spring Repository,我們可以使用@DataJpaTest,這樣我們就可以使用TestEntityManager來測試我們Repository的功能了。
@RunWith(SpringRunner.class)@DataJpaTestpublic class ClientRepositoryTest { @Autowired private TestEntityManager entityManager; @Autowired private ClientRepository clientRepository; @Test public void testFindByName() { entityManager.persist(new Client("Wang")); Optional<Client> client = clientRepository.findByName("Wang"); assertEquals("Wang", client.get().getName()); } }
測試JSON的序列化和反序列化,需要用@JsonTest
@RunWith(SpringRunner.class) @JsonTestpublic class CustomerJsonTests { private JacksonTester<Customer> json; @Test public void serializeJson() { Customer customer= new Customer( "wang"); assertThat(this.json.write(details)) .extractingJsonPathStringValue("@.name") .isEqualTo("wang"); } }
測試Spring MVC Controller,需要用到@WebMvcTest
@Autowired private MockMvc mockMvc; @MockBean private OrderEntryService orderEntryService; @Test public void updateOrderEntryByIDTest() throws Exception { final String orderEntryJson = IOUtils.toString(this.getClass().getResourceAsStream("/static/meta-data/orderentry-example.json"), CharEncoding.UTF_8 ); Mockito.when(orderEntryService.findById(Mockito.anyLong())).thenReturn(entry); RequestBuilder requestBuilder = MockMvcRequestBuilders.patch("/orderentries/1").accept( MediaType.APPLICATION_JSON) .contentType(contentType) .content(orderEntryJson); MvcResult result= mockMvc.perform(requestBuilder).andReturn(); assertEquals(HttpStatus.ACCEPTED.value(),result.getResponse().getStatus());