2016-08-15 3 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 Worth, указывая на то, что с 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; 
    } 
} 
Смежные вопросы