Spring Boot的单元测试(Unit Test)(一)

2017-05-06 01:15

最近做了一些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());