使用 RestAssured 验证模式。 InvalidSchemaException:致命:无效 JSON 架构,无法继续

Validating Schema using RestAssured. InvalidSchemaException: fatal: invalid JSON Schema, cannot continue

我正在尝试使用 Rest Assured 验证响应模式并遇到错误。它显示验证期望一个字符串作为 ID,但它返回整数。其次,它跳过了模型中的许多字段,我想知道为什么。我如何获得架构验证。

这是我在验证模式时使用的代码

@Test(priority = 1)
    public static void searchForUsername( ) throws Throwable {
        Response response = RestAssured.given().queryParam(getProperties().getProperty("project.query"), getProperties().getProperty("project.username"))
                .get(Init.initProperties() +getProperties().getProperty("users.pathURL"));
        response.then().assertThat().body(matchesJsonSchemaInClasspath("schema/users.json")).contentType(ContentType.JSON).statusCode(200).log().all();
        List<UserItem> userItems = response.as(new TypeRef<>() {});
        for ( UserItem u: userItems ) {
            if ( (Integer) response.jsonPath().getList("id").get(0) == u.getId() ){
                userId = u.getId();
                MyLogger.info("This is getting the user ID of Delphine " + userId);
            }
        }
    }

这是架构。这是 users.json

{
    "id": 9,
    "name": "Glenna Reichert",
    "username": "Delphine",
    "email": "Chaim_McDermott@dana.io",
    "address": {
      "street": "Dayna Park",
      "suite": "Suite 449",
      "city": "Bartholomebury",
      "zipcode": "76495-3109",
      "geo": {
        "lat": "24.6463",
        "lng": "-168.8889"
      }
    },
    "phone": "(775)976-6794 x41206",
    "website": "conrad.com",
    "company": {
      "name": "Yost and Sons",
      "catchPhrase": "Switchable contextually-based project",
      "bs": "aggregate real-time technologies"
    }
  }

模式验证错误。

io.restassured.module.jsv.JsonSchemaValidationException: com.github.fge.jsonschema.core.exceptions.InvalidSchemaException: fatal: invalid JSON Schema, cannot continue
Syntax errors:
[ {
  "level" : "warning",
  "schema" : {
    "loadingURI" : "file:/Users/wikiwoo/MyProject/target/classes/schema/users.json#",
    "pointer" : ""
  },
  "domain" : "syntax",
  "message" : "the following keywords are unknown and will be ignored: [address, company, email, name, phone, username, website]",
  "ignored" : [ "address", "company", "email", "name", "phone", "username", "website" ]
}, {
  "level" : "error",
  "message" : "value has incorrect type (found integer, expected one of [string])",
  "domain" : "syntax",
  "schema" : {
    "loadingURI" : "file:/Users/wikiwoo/MyProject/target/classes/schema/users.json#",
    "pointer" : ""
  },
  "keyword" : "id",
  "found" : "integer",
  "expected" : [ "string" ]
} ]
    level: "fatal"


    at io.restassured.module.jsv.JsonSchemaValidator.matchesSafely(JsonSchemaValidator.java:233)
    at io.restassured.module.jsv.JsonSchemaValidator.matchesSafely(JsonSchemaValidator.java:75)
    at org.hamcrest.TypeSafeMatcher.matches(TypeSafeMatcher.java:65)
    at org.hamcrest.Matcher$matches.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:139)
    at io.restassured.assertion.BodyMatcher.validate(BodyMatcher.groovy:76)
    at io.restassured.assertion.BodyMatcher$validate[=13=].call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:157)
    at io.restassured.assertion.BodyMatcherGroup$_validate_closure2.doCall(BodyMatcherGroup.groovy:47)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:107)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:323)
    at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:263)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1035)
    at groovy.lang.Closure.call(Closure.java:412)
    at groovy.lang.Closure.call(Closure.java:428)
    at org.codehaus.groovy.runtime.DefaultGroovyMethods.collect(DefaultGroovyMethods.java:3575)
    at org.codehaus.groovy.runtime.DefaultGroovyMethods.collect(DefaultGroovyMethods.java:3560)
    at org.codehaus.groovy.runtime.DefaultGroovyMethods.collect(DefaultGroovyMethods.java:3660)
    at org.codehaus.groovy.runtime.dgm1.invoke(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:247)
    at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:56)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:139)
    at io.restassured.assertion.BodyMatcherGroup.validate(BodyMatcherGroup.groovy:47)
    at io.restassured.assertion.BodyMatcherGroup$validate.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:157)
    at io.restassured.internal.ResponseSpecificationImpl$HamcrestAssertionClosure.validate(ResponseSpecificationImpl.groovy:480)
    at io.restassured.internal.ResponseSpecificationImpl$HamcrestAssertionClosure$validate.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:139)
    at io.restassured.internal.ResponseSpecificationImpl.validateResponseIfRequired(ResponseSpecificationImpl.groovy:674)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.codehaus.groovy.runtime.callsite.PlainObjectMetaMethodSite.doInvoke(PlainObjectMetaMethodSite.java:43)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:193)
    at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:61)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:51)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:171)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:185)
    at io.restassured.internal.ResponseSpecificationImpl.body(ResponseSpecificationImpl.groovy:98)
    at io.restassured.internal.ValidatableResponseOptionsImpl.body(ValidatableResponseOptionsImpl.java:238)
    at io.restassured.internal.ValidatableResponseImpl.super$body(ValidatableResponseImpl.groovy)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:107)
    at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:323)
    at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1268)
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodOnSuperN(ScriptBytecodeAdapter.java:144)
    at io.restassured.internal.ValidatableResponseImpl.body(ValidatableResponseImpl.groovy:293)
    at io.restassured.internal.ValidatableResponseImpl.body(ValidatableResponseImpl.groovy)
    at io.christdoes.test.testcases.TestCases.searchForUsername(TestCases.java:47)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:124)
    at org.testng.internal.Invoker.invokeMethod(Invoker.java:583)
    at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:719)
    at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:989)
    at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:125)
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:109)
    at org.testng.TestRunner.privateRun(TestRunner.java:648)
    at org.testng.TestRunner.run(TestRunner.java:505)
    at org.testng.SuiteRunner.runTest(SuiteRunner.java:455)
    at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:450)
    at org.testng.SuiteRunner.privateRun(SuiteRunner.java:415)
    at org.testng.SuiteRunner.run(SuiteRunner.java:364)
    at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
    at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:84)
    at org.testng.TestNG.runSuitesSequentially(TestNG.java:1208)
    at org.testng.TestNG.runSuitesLocally(TestNG.java:1137)
    at org.testng.TestNG.runSuites(TestNG.java:1049)
    at org.testng.TestNG.run(TestNG.java:1017)
    at com.intellij.rt.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:66)
    at com.intellij.rt.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:109)
Caused by: com.github.fge.jsonschema.core.exceptions.InvalidSchemaException: fatal: invalid JSON Schema, cannot continue
Syntax errors:
[ {
  "level" : "warning",
  "schema" : {
    "loadingURI" : "file:/Users/wikiwoo/MyProject/target/classes/schema/users.json#",
    "pointer" : ""
  },
  "domain" : "syntax",
  "message" : "the following keywords are unknown and will be ignored: [address, company, email, name, phone, username, website]",
  "ignored" : [ "address", "company", "email", "name", "phone", "username", "website" ]
}, {
  "level" : "error",
  "message" : "value has incorrect type (found integer, expected one of [string])",
  "domain" : "syntax",
  "schema" : {
    "loadingURI" : "file:/Users/wikiwoo/MyProject/target/classes/schema/users.json#",
    "pointer" : ""
  },
  "keyword" : "id",
  "found" : "integer",
  "expected" : [ "string" ]
} ]
    level: "fatal"

    at com.github.fge.jsonschema.processors.validation.InstanceValidator.process(InstanceValidator.java:114)
    at com.github.fge.jsonschema.processors.validation.ValidationProcessor.process(ValidationProcessor.java:56)
    at com.github.fge.jsonschema.processors.validation.ValidationProcessor.process(ValidationProcessor.java:34)
    at com.github.fge.jsonschema.core.processing.ProcessingResult.of(ProcessingResult.java:79)
    at com.github.fge.jsonschema.main.JsonSchemaImpl.doValidate(JsonSchemaImpl.java:77)
    at com.github.fge.jsonschema.main.JsonSchemaImpl.validate(JsonSchemaImpl.java:100)
    at com.github.fge.jsonschema.main.JsonSchemaImpl.validate(JsonSchemaImpl.java:110)
    at io.restassured.module.jsv.JsonSchemaValidator.matchesSafely(JsonSchemaValidator.java:227)
    ... 90 more

我认为错误信息很清楚:

"message" : "value has incorrect type (found integer, expected one of [string])",

正如您在 json 中看到的那样,id 是一个整数

{
"id": 9,
..
}

解决方法如下:

  1. 检查你的架构,某处有一个声明 id 是一个字符串,而不是一个整数
  2. 将此声明更改为整数
  3. 运行 再次,应该工作

注意:我不知道json中的数据是否真实,在将生产数据复制粘贴到SO[=12之前仔细检查=]

我经常用这个工具来生成schema,可以节省很多时间。 https://www.liquid-technologies.com/online-json-to-schema-converter

您的回复架构是,我已经用您的回复进行了测试。

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "id": {
      "type": "number"
    },
    "name": {
      "type": "string"
    },
    "username": {
      "type": "string"
    },
    "email": {
      "type": "string"
    },
    "address": {
      "type": "object",
      "properties": {
        "street": {
          "type": "string"
        },
        "suite": {
          "type": "string"
        },
        "city": {
          "type": "string"
        },
        "zipcode": {
          "type": "string"
        },
        "geo": {
          "type": "object",
          "properties": {
            "lat": {
              "type": "string"
            },
            "lng": {
              "type": "string"
            }
          },
          "required": [
            "lat",
            "lng"
          ]
        }
      },
      "required": [
        "street",
        "suite",
        "city",
        "zipcode",
        "geo"
      ]
    },
    "phone": {
      "type": "string"
    },
    "website": {
      "type": "string"
    },
    "company": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        },
        "catchPhrase": {
          "type": "string"
        },
        "bs": {
          "type": "string"
        }
      },
      "required": [
        "name",
        "catchPhrase",
        "bs"
      ]
    }
  },
  "required": [
    "id",
    "name",
    "username",
    "email",
    "address",
    "phone",
    "website",
    "company"
  ]
}