java - Spring Boot 1.4 - 如何使用验证来测试 Controller

标签 java spring-mvc testing spring-boot integration-testing

Spring Boot 1.4 有许多优秀的特性,包括@DataJpaTest 注解,可以自动唤醒类路径嵌入式数据库以进行测试。据我所知,它不会在同一类的范围内与 TestRestTemplate 结合使用。

以下测试将不起作用:

@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]

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

@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 不应与 Controller 一起使用。

有没有办法使用 Spring Boot 1.4 测试功能来测试具有这种架构的 Controller ?

最佳答案

您对 @DataJpaTest 的理解有点不对劲。来自文档“可以在测试仅关注 JPA 组件时使用”。如果你想测试你的 Controller 层,你不想使用这个注释,因为没有任何 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());
    }
}

不确定您是如何连接 validator 和服务的,所以假设您是自动连接它们的。

@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;
    }
}

关于java - Spring Boot 1.4 - 如何使用验证来测试 Controller ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38961112/

相关文章:

java - 在 MySQL 的选择查询中将 VARBINARY 值转换为字符串?

java - JSP和Spring MVC的多个复选框,如何获取值

ruby-on-rails - capybara ::ElementNotFound:找不到字段

C# SqlDataReader 接口(interface)与 HasRows、Read() 和 NextResult()

scala - 是否可以让 SBT 尊重 Scalatest 的 DoNoDiscover 注释?

java - Android - EBADF(错误文件号)OnClickInfoMarker

java - 在应用程序小部件中设置背景色调

java - 我的返回声明有什么问题?

spring-mvc - 在 Spring Boot 1.4 中测试 Spring MVC 切片时出现问题

java - spring Rest api Controller 的缓存响应