【问题标题】:Full Json match with RestAssured与 RestAssured 的完整 Json 匹配
【发布时间】:2017-06-23 08:29:08
【问题描述】:

我正在使用 REST-Assured 来测试一些 API。我的 API 清楚地使用 JSON 响应,如果这是响应,则根据文档:

{
    "id": "390",
    "data": {
        "leagueId": 35,
        "homeTeam": "Norway",
        "visitingTeam": "England",
    },
    "odds": [{
        "price": "1.30",
        "name": "1"
    },
    {
        "price": "5.25",
        "name": "X"
    }]
}

我可以这样测试:

@Test
public void givenUrl_whenSuccessOnGetsResponseAndJsonHasRequiredKV_thenCorrect() {
   get("/events?id=390")
      .then()
         .statusCode(200)
         .assertThat()
            .body("data.leagueId", equalTo(35)); 
}

这当然是可读的,但我会全面比较 JSON(即:这是 JSON 响应;这是一个罐装 JSON - 资源文件将是完美的 - 那些 JSON 是否相等?)。 REST-Assured 是否提供类似的功能,或者我需要手动制作。

【问题讨论】:

  • 你有没有研究过 json 模式验证:github.com/rest-assured/rest-assured/wiki/…
  • 我不需要模式验证。我需要一个 result 验证(不仅是类型,而且是值)。这对于 JSON Schema 来说会很麻烦(假设有可能)

标签: json rest rest-assured


【解决方案1】:

使用 RestAssured 的 JsonPath 将 json 文件解析为 Map,然后与 Hamcrest Matchers 进行比较。这样,订单等就无关紧要了。

import static org.hamcrest.Matchers.equalTo;
import io.restassured.path.json.JsonPath;

...

JsonPath expectedJson = new JsonPath(new File("/path/to/expected.json"));

given()
    ...
    .then()
    .body("", equalTo(expectedJson.getMap("")));

【讨论】:

    【解决方案2】:

    Karate 正是您正在寻找的 - 您可以一步完成 JSON 有效负载的完整相等匹配。

    对于您拥有动态值(生成的键、时间戳)的情况,空手道提供了一种非常优雅的方式让您忽略(或仅验证其格式)这些键。

    创建空手道的一个主要动机是想出一个更好的替代 REST-assured。您可以参考这份文档,它可以帮助您评估空手道并在您的组织中为空手道提供案例:Karate vs REST-assured

    【讨论】:

      【解决方案3】:

      REST Assured 不支持 JSON 比较,仅支持您在问题中的架构和正文部分。您可以做的是在Hamcrest JSON SameJSONAs 中使用 Hamcrest 的 JSON 比较器SameJSONAs

      【讨论】:

        【解决方案4】:

        如果有人正在寻找不解析 json 文件的方法。

        您可以在开始时使用Matchers.aMapWithSize(size)检查正文大小,然后照常检查内容。

        例子:

        @Test
        public void getAccount_forbidden_whenUserIsAnonymous() {
            RestAssured
                .get("/account")
                .then()
                .statusCode(HttpServletResponse.SC_FORBIDDEN)
                .body("", Matchers.aMapWithSize(5),
                      "timestamp", Matchers.notNullValue(),
                      "status", Matchers.equalTo(HttpServletResponse.SC_FORBIDDEN),
                      "error", Matchers.equalTo("Forbidden"),
                      "message", Matchers.equalTo("Access Denied"),
                      "path", Matchers.equalTo("/account"));
        }
        

        【讨论】:

          【解决方案5】:

          您可以在 RestAssured 中使用带有 JSON SCHEMA 的验证。

          试试这个代码:

          // 基础测试[BaseTest.java]

          public class BaseTest {
          
              protected RequestSpecification requestSpecificationToMerge = new RequestSpecBuilder()
                      .setBaseUri("BASE URL")
                      .setContentType(ContentType.JSON)
                      .build();
          
              @BeforeMethod
              public void setFilter() {
                  RestAssured.filters(new AllureRestAssured());
              }
          
          }
          

          // 测试[Home.java]

          public class Home extends BaseTest {
              
              @Test(priority = 0)
              public void getHome() {
                  
                  given()
                  .spec(requestSpecificationToMerge)
                  .basePath("/your endpoint")
                  .when()
                  .get()
                  .then()
                  .log().body()
                  .body(matchesJsonSchemaInClasspath("home.json"));
              }
          

          // JSON SCHEMA [home.json]

          {
              "type": "object",
              "required": [
                  "data",
                  "meta",
                  "status"
              ],
              "properties": {
                  "data": {
                      "type": ["array", "null"],
                      "items": {
                          "type": "object",
                          "required": [
                              "id",
                              "title",
                              "sorting"
                          ],
                          "properties": {
                              "id": {
                                  "type": "integer"
                              },
                              "title": {
                                  "type": "string"
                              },
                              "sorting": {
                                  "type": "integer"
                              }
                          }
                      }
                  },
                  "meta": {
                      "type": ["object", "null"],
                      "required": [
                          "pagination"
                      ],
                      "items": {
                          "type": "object",
                          "required": [
                              "current_page",
                              "per_page",
                              "total",
                              "total_page"
                          ],
                          "properties": {
                              "current_page": {
                                  "type": "integer"
                              },
                              "per_page": {
                                  "type": "integer"
                              },
                              "total": {
                                  "type": "integer"
                              },
                              "total_page": {
                                  "type": "integer"
                              }
                          }
                      }
                  },
                  "status": {
                      "type": "object",
                      "required": [
                          "code",
                          "message_client",
                          "message_server"
                      ],
                      "properties": {
                          "code": {
                              "type": "integer",
                              "enum": [
                                  200,
                                  404
                              ]
                          },
                          "message_client": {
                              "type": "string"
                          },
                          "message_server": {
                              "type": "string"
                          }
                      }
                  }
              }
          }
          

          【讨论】:

            【解决方案6】:

            简单的方法:

            String s = "{\"ip\": \"your_ip\"}";
            given().log().all().contentType(ContentType.JSON).get("http://ip.jsontest.com/").then().log().all().assertThat().body(containsString(s))
            

            不简单的方法:你可以创建自定义匹配器或使用 jsonpath,它有 comapre jsons 的选项。

            【讨论】:

              【解决方案7】:

              显然,rest-assured 仅提供验证架构的功能,如 here 所述。

              但是,使用jackson-databindjunit 进行精确比较非常简单。

              我们应该编写一个函数,将rest-assured返回的正文与resources目录中的文件进行比较

              import org.junit.Assert;
              import com.fasterxml.jackson.databind.ObjectMapper;
              import com.fasterxml.jackson.databind.json.JsonMapper;
              import com.fasterxml.jackson.databind.node.ObjectNode;
              
              void assertJsonEquals(String expectedJson, ResponseBodyExtractionOptions actualBody) throws IOException {
                  Assert.assertNotNull("The request returned no body", expectedJson);
              
                  final ObjectMapper mapper = new ObjectMapper();
                  Assert.assertEquals(
                          mapper.readTree(Objects.requireNonNull(getClass().getClassLoader().getResource(expectedJsonPath)).openStream().readAllBytes()),
                          mapper.readTree(body.asByteArray())
                  );
              }
              

              然后,如下所示使用它

              final ResponseBodyExtractionOptions actualBody = given()
                      .accept("application/json")
                      .contentType(MediaType.APPLICATION_JSON)
                  .when()
                      .get("...")
                  .then()
                      .extract().body();
              assertJsonEquals("expected-payload.json", actualBody);
              

              【讨论】:

                【解决方案8】:

                您可以使用 JSONAssert 库来匹配整个 JSON 响应。 我最近写了一个blog 来说明如何实现它。 你可能想看看它。

                以下是如何使用该库的基本用法:

                    JSONAssert.assertEquals(expectedResponse, actualResponse, JSONCompareMode.LENIENT);
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2016-06-27
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多