使用邮递员返回错误请求,但未在单元测试 Spring Boot 中返回

Posted

技术标签:

【中文标题】使用邮递员返回错误请求,但未在单元测试 Spring Boot 中返回【英文标题】:bad request returned using postman but not in unit testing spring boot 【发布时间】:2020-12-05 06:05:09 【问题描述】:

我有一个具有唯一字段“名称”的类别实体。

我正在使用自定义的唯一注释来验证数据,并且效果很好。

我正在尝试在我的 Spring Boot 应用程序上测试我的控制器,如果数据重复(唯一名称),我想检查请求是否返回 400 状态。

在邮递员中它按预期工作并返回 400 状态和错误列表。

在单元测试中,它返回一个空主体的 201 状态(但实际上,返回 201 意味着主体包含新创建的实体!)

这是我的测试:

    @Test
    public void testIfAdminCanCreateCategory_expect400BecauseCategoryAlreadyExist() throws Exception 
        // json
        String data = "\"name\" : \"CATEGORY\"";
        mockMvc().with(keycloakAuthenticationToken().authorities("ROLE_admin")).perform(post("/categories").content(data).contentType("application/json"))
                .andDo(print())
                .andDo(r -> mockMvc().with(keycloakAuthenticationToken().authorities("ROLE_admin"))
                        .perform(post("/categories").content(data).contentType("application/json"))
                        .andExpect(status().isBadRequest()));
    

我的控制器:

    @PostMapping
    @PreAuthorize("hasRole('ROLE_admin')")
    public HttpEntity<MainCategory> create(@Valid @RequestBody CreateMainCategory createMainCategory)
    
        return ResponseEntity.status(HttpStatus.CREATED).body(mainCategoryService.create(createMainCategory));
    

我的服务:

    @Override
    public MainCategory create(CreateMainCategory createMainCategory) 
        MainCategory mainCategory = new MainCategory();
        mainCategory.setName(createMainCategory.getName().toUpperCase());
        return mainCategoryRepository.save(mainCategory);
    

我的实体:

@Entity
@EntityListeners( AuditingEntityListener.class  )
@Data
public class MainCategory 

    @Id @GeneratedValue private Long id;

    private String name;

    @CreatedBy
    private String createdBy;

    @OneToMany(cascade = CascadeType.REMOVE, mappedBy = "mainCategory")
    List<Category> categories;

来自日志的请求:

MockHttpServletRequest:
      HTTP Method = POST
      Request URI = /categories
       Parameters = 
          Headers = [Content-Type:"application/json;charset=UTF-8", Content-Length:"21"]
             Body = "name" : "CATEGORY"
    Session Attrs = SPRING_SECURITY_CONTEXT=org.springframework.security.core.context.SecurityContextImpl@6989924: Authentication: org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken@6989924: Principal: user; Credentials: [PROTECTED]; Authenticated: true; Details: org.keycloak.adapters.springsecurity.account.SimpleKeycloakAccount@40fd518f; Granted Authorities: ROLE_admin

来自日志的响应:

MockHttpServletResponse:
           Status = 201
    Error message = null
          Headers = [Vary:"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY"]
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

java.lang.AssertionError: Status 
Expected :400
Actual   :201

【问题讨论】:

看看这里how-to-test-if-valid-annotation-is-working 【参考方案1】:

问题与 save() 方法有关,即使在我的属性文件上定义 mysql 数据库时它也没有保存任何实体(这解释了 201 created status 中的空主体)。

一种解决方案是使用 H2 数据库进行测试,将其配置添加到单独的属性文件中(在我的情况下为 product-service-test.yml),并将 @ActiveProfiles("test") 添加到测试类中。

【讨论】:

【参考方案2】:

在测试用例中,没有任何地方显示数据是重复的。您在测试用例中定义字符串数据并在那里使用它。因此它提供了 200 个已创建状态。

在实体创建中,名称没有被定义为唯一的。

@Column(unique=true)
private String name;

默认为假。

【讨论】:

以上是关于使用邮递员返回错误请求,但未在单元测试 Spring Boot 中返回的主要内容,如果未能解决你的问题,请参考以下文章

应用程序在 Apple 崩溃但未在测试中

Chrome 获取 Set-cookie 标头但未将其放入新请求中

获取 Websocket 错误但未在代码中使用 Websocket

axios发布请求不返回响应错误

发布请求总是在 JMeter 中返回错误

使用邮递员发布请求后,spring boot 服务器返回错误 400