【问题标题】:Spring boot REST: cannot test validation of @RequestParamSpring Boot REST:无法测试@RequestParam 的验证
【发布时间】:2020-07-25 14:38:46
【问题描述】:

我想测试 Spring Boot API 的控制器,其类结构如下:

控制器:

@RestController
@RequestMapping("/member-management")
@Validated
public class MemberManagementController {

    private final MemberManagementService memberManagementService;

    public MemberManagementController(MemberManagementService memberManagementService) {
        this.memberManagementService = memberManagementService;
    }

    @GetMapping(value = "/view-member")
    public ResponseEntity<?> viewMember(
            @NotBlank(message = "username must not be blank!!") 
            @Size(max = 20, message = "maximum size of username id is 20!!") 
            @RequestParam("username") String username) {
        ...
    }
...

控制器建议:

@ControllerAdvice
public class CustomRestExceptionHandler extends ResponseEntityExceptionHandler {
    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseEntity<Object> handleConstaintViolatoinException(final ConstraintViolationException ex) {
        List<String> details = new ArrayList<>();
        Set<ConstraintViolation<?>> violations = ex.getConstraintViolations();
        for (ConstraintViolation<?> violation : violations) {
            details.add(violation.getMessage());
        }
        ApiErrorResUtil error = new ApiErrorResUtil(String.valueOf(HttpStatus.BAD_REQUEST.value()),
                "Request param error", details);
        return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
    }
...
}

单元测试:

@RunWith(MockitoJUnitRunner.class)
public class MemberManagementControllerTest {

    @InjectMocks
    private MemberManagementController memberManagementController;

    @Mock
    private MemberManagementService memberManagementService;

    private MockMvc mockMvc;

    @Before // Execute before each test method
    public void setup() {
        this.mockMvc = MockMvcBuilders.standaloneSetup(memberManagementController)
                .setControllerAdvice(new CustomRestExceptionHandler()) // add ControllerAdvice to controller test
                .build();
    }

    @Test 
    public void viewMember_usernameSizeExceedsMaximumLimit() throws Exception {
        // Value from client
        String username = "a12345678901234567890"; // 21 characters

        MemberResDtoDataDummy memberResDtoDataDummy = new MemberResDtoDataDummy();

        when(memberManagementService.viewMember(username)).thenReturn(memberResDtoDataDummy.getMember1());

        mockMvc.perform(get("/member-management/view-member").param("username", username))
                .andExpect(status().isBadRequest()).andReturn();
    }

问题:

java.lang.AssertionError: Status expected:<400> but was:<200>
    at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:59)
    ...

谁能帮我解决这个问题,为什么预期状态是 200 而不是 400,其他输入无效参数的 POST、PUT、PATCH、DELETE 请求方法的测试仍然可以正常工作:(

【问题讨论】:

  • 永远不要使用standaloneSetup;它无法设置控制器将在其中运行的实际上下文(日期等项目的 JSON 格式是臭名昭著的失败案例)。使用 @SpringBootTest 并自动连接您的 MockMvc。 (附带说明一下,您没有使用标准 REST 约定,我强烈建议您这样做。命名资源,即member,并且“view”已通过 GET 进行通信,所以GET /members/{id}(如果你知道ID)或GET /members?username=,通常总是返回一个数组,因为它是一个搜索结果。)

标签: java spring spring-boot api unit-testing


【解决方案1】:

如果您想在不启动服务器的情况下测试您的 UI 层,您必须将此测试定义为 spring-boot 测试并自动连接 MockMvc

@SpringBootTest @AutoConfigureMockMvc

这个类注解会在没有服务器的情况下加载所有的applicationContext。

如果你只是想加载你的 web 层,把这个注解放在你的测试类上。

@WebMvcTest

有了这个注解,Spring Boot 只实例化 web 层而不是整个上下文。

在这两种情况下,您都必须autowired MockMvc 类型。

【讨论】:

    猜你喜欢
    • 2016-12-01
    • 2019-11-06
    • 2018-08-13
    • 2017-07-25
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 2017-11-02
    • 2016-11-06
    相关资源
    最近更新 更多