2016-08-15 58 views
1

Spring Boot 1.4具有许多很好的功能,包括@DataJpaTest注释,可以自动唤醒用于测试目的的类路径嵌入式数据库。据我所知,它不会与TestRestTemplate在同一类的边界中结合使用。Spring Boot 1.4 - 如何通过验证来测试控制器

下面的测试将无法正常工作:

@RunWith(SpringRunner.class) 
@SpringBootTest 
@DataJpaTest 
public class PersonControllerTest { 

    private Logger log = Logger.getLogger(getClass()); 

    private Category category; 

    @Autowired 
    private TestRestTemplate restTemplate; 

    @Autowired 
    private TestEntityManager entityManager; 

    @Before 
    public void init() { 

     log.info("Initializing..."); 

     category = entityManager.persist(new Category("Staff")); 
    } 

    @Test 
    public void personAddTest() throws Exception { 

     log.info("PersonAdd test starting..."); 

     PersonRequest request = new PersonRequest("Jimmy"); 

     ResponseEntity<String> response = restTemplate.postForEntity("/Person/Add", request, String.class); 
     assertEquals(HttpStatus.OK, response.getStatusCode()); 

     log.info("PersonAdd test passed"); 
    } 

在测试过程中的,会引发异常的启动:

Unsatisfied dependency expressed through field 'restTemplate': 
No qualifying bean of type [org.springframework.boot.test.web.client.TestRestTemplate] 

然后猜测,切换到基于推荐模拟切片的方法,但它将不会在那里工作,因为控制器看起来像这样:

@RequestMapping(value="/Person/Add", method=RequestMethod.POST) 
public ResponseEntity personAdd(@Valid @RequestBody PersonRequest personRequest, 
           Errors errors) 

    personValidator.validate(personRequest, errors): 

    if (errors.hasErrors()) 
     return new ResponseEntity(HttpStatus.BAD_REQUEST); 

    personService.add(personRequest); 

    return new ResponseEntity(HttpStatus.OK); 
} 

...很容易根据文档建议嘲笑personService,但如何与errors对象在这种情况下不可嘲笑?据我所知,没有办法嘲笑它,因为它不是类字段或方法的返回值。

所以,我不能使用分片方法或集成方法来测试上面的代码,因为@DataJpaTest不应该与控制器一起使用。

有没有一种方法可以使用Spring Boot 1.4测试功能来测试这种架构的控制器?

+0

而不是嘲笑控制器的方法,你可以模拟URL调用。这将负责错误验证。检查这篇文章http://stackoverflow.com/a/12308698/5343269 – 11thdimension

+0

@ 11thdimension值得指出的是,在Spring Boot 1.4中,注释略有改变,您不需要创建MockMvc,而是可以自动装入。详情请参阅https://spring.io/blog/2016/04/15/testing-improvements-in-spring-boot-1-4。 –

+0

@wilddev如果你可以包含你正在尝试使用的测试类,那么我们可以提供一些关于如何使它以你期望的方式工作的建议。 –

回答

3

您对@DataJpaTest的理解有点偏离。从文档“仅当测试只关注JPA组件时才能使用”。如果您想测试控制器层,则不需要使用此注释,因为没有任何WebMvc组件会加载到应用程序上下文中。您反而想使用@WebMvcTest并使用您正在测试的@Controller

@RunWith(SpringRunner.class) 
@WebMvcTest(PersonController.class) 
public class PersonControllerTest { 
    @Autowired 
    private MockMvc mockMvc; 

    @MockBean 
    PersonValidator personValidator; 

    @MockBean 
    PersonService personService; 

    @Test 
    public void personAddTest() throws Exception { 
     String content = "{\"name\": \"Jimmy\"}"; 
     mockMvc.perform(post("/Person/Add").contentType(MediaType.APPLICATION_JSON).characterEncoding("UTF-8") 
       .accept(MediaType.APPLICATION_JSON).content(content)).andExpect(status().isOk()); 
    } 

    @Test 
    public void personAddInvalidTest() throws Exception { 
     String content = "{\"noname\": \"Jimmy\"}"; 
     mockMvc.perform(post("/Person/Add").contentType(MediaType.APPLICATION_JSON).characterEncoding("UTF-8") 
       .accept(MediaType.APPLICATION_JSON).content(content)).andExpect(status().isBadRequest()); 
    } 
} 

不知道你如何连接验证器和服务,所以只是假设你自动装配它们。

@Controller 
public class PersonController { 
    private PersonValidator personValidator; 
    private PersonService personService; 

    public PersonController(PersonValidator personValidator, PersonService personService) { 
     this.personValidator = personValidator; 
     this.personService = personService; 
    } 

    @RequestMapping(value = "/Person/Add", method = RequestMethod.POST) 
    public ResponseEntity<String> personAdd(@Valid @RequestBody PersonRequest personRequest, Errors errors) { 
     personValidator.validate(personRequest, errors); 

     if (errors.hasErrors()) { 
      return new ResponseEntity<String>(HttpStatus.BAD_REQUEST); 
     } 
     personService.add(personRequest); 

     return new ResponseEntity<String>(HttpStatus.OK); 
    } 
} 

样本PersonRequest因为我不知道那里还有什么东西。请注意,名称上的一个验证为@NotNull,因为我想要展示如何使用Errors对象的方法。

public class PersonRequest { 
    @NotNull 
    private String name; 

    public PersonRequest() { 
    } 

    public PersonRequest(String name) { 
     this.name = name; 
    } 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 
}