【问题标题】:Mock a JSON request parameter using Quarkus and RestAssured使用 Quarkus 和 RestAssured 模拟 JSON 请求参数
【发布时间】:2021-07-08 00:18:32
【问题描述】:

使用 Quarkus,我有以下 API。

@RequestScoped
@Path("/api/v1")
public class MyApi {

    @POST
    @Consumes(APPLICATION_JSON)
    public Response create(Entity entityToCreate) {
        if (entityToCreate.isValid()) {
            // create the entity in my app...
            return Response.ok().build();
        } else {
            return Response.status(BAD_REQUEST).build();
        }
    }
}

我的Entity 班级看起来像这样

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

public class Entity {

    private final String property1;
    private final String property2;
    // ...

    @JsonCreator
    public Entity(@JsonProperty("property1") String property1,
                  @JsonProperty("property2") String property2,
                  // ...
    ){
        this.property1 = property1;
        this.property2 = property2;
        // ...
    }

    // getters for every property...

    public boolean isValid() {
        // check if the entity is valid, then return true or false
    }
}

在我的单元测试中,我想要实现的目标如下:

import static io.restassured.RestAssured.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

@QuarkusTest
public class MyApiTest {
    
    private final Entity entityMock = mock(Entity.class);
    
    @Test
    public void shouldCreateEntityWhenValid(){
        when(entityMock.isValid()).thenReturn(true);

        given()
            .contentType(ContentType.JSON)
            .body(entityMock)
        .when()
            .post("/api/v1")
        .then()
            .statusCode(200);
    }

    @Test
    public void shouldNotCreateEntityWhenInvalid(){
        when(entityMock.isValid()).thenReturn(false);

        given()
            .contentType(ContentType.JSON)
            .body(entityMock)
        .when()
            .post("/api/v1")
        .then()
            .statusCode(400);
    }
}

目前,我遇到以下错误,因为杰克逊试图反序列化模拟。

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.mockito.internal.invocation.mockref.MockWeakReference and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: blah blah blah... )

【问题讨论】:

    标签: java mockito junit5 rest-assured quarkus


    【解决方案1】:

    只需创建实体的真实实例并让验证发生。

    Rest Assured 将在测试中发布一个实际的 HTTP 请求,因此它将您的模拟序列化为 JSON。当实现处理 HTTP 请求时,请求正文随后被反序列化为实体。该实体是在内部实例化的,因此它与测试中创建的实例不同。

    【讨论】:

    • 我不想实例化一个真实的实体。导致有效或无效对象的条件不是MyApi 类或其测试类的关注点。我不想必须选择实体的特定有效或无效配置。
    • 反序列化是由框架完成的,所以你真的别无选择。如果你想分离验证问题,你不能用这样的集成测试来测试它。
    • 您仍然可以通过为实体编写单元测试来单独测试验证。但是在控制器中处理验证需要一些东西来实际触发验证。
    • 我单独测试了验证。在控制器中,我最终可能会混合使用 RestAssured 测试和更简单的 JUnit 测试,在这些测试中我将自己调用控制器方法...
    • 如果你真的想分离验证问题,我建议抛出 ConstraintViolationException 或使用 Java 验证器。这样一来,您只需要一个异常处理程序,就可以忘记在每个控制器方法中手动处理验证状态。
    【解决方案2】:

    我最终混合了几种测试技术,以验证 JSON 映射和方法行为。

    import static io.restassured.RestAssured.given;
    import static org.mockito.Mockito.mock;
    import static org.mockito.Mockito.when;
    
    @QuarkusTest
    public class MyApiTest {
        
        private final Entity entityMock = mock(Entity.class);
        private final Entity validEntity = // [...] instantiate a valid entity here
        
        private MyApi api;
        
        @BeforeEach
        void beforeEach() {
            myApi = new MyApi();
        }    
    
        // this test validates both the JSON parsing and the valid entity case
        @Test
        public void shouldCreateEntityWhenValid(){ 
            given()
                .contentType(ContentType.JSON)
                .body(validEntity)
            .when()
                .post("/api/v1")
            .then()
                .statusCode(200);
        }
        
        // this test validates the invalid entity case
        @Test
        public void shouldNotCreateEntityWhenInvalid(){
            when(entityMock.isValid()).thenReturn(false);
    
            Response response = myApi.create(entityMock);
    
            assertThat(response.getStatus()).isEqualTo(400);
        }
    }
    

    【讨论】:

    • 第一个测试并没有按照您的想法进行。再读一遍我的解释。
    • 感谢您的警惕。这是一个错误的复制/粘贴。我在第一个测试用例中实例化了一个真实有效的实体。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-18
    • 1970-01-01
    相关资源
    最近更新 更多