使用 NJsonSchema 在单元测试中解析 JSON $ref
Resolve JSON $ref in unit tests using NJsonSchema
我已将我的 JSON 架构拆分为多个文件,并根据需要以标准方式引用它们 ("$ref": http://rootpath/otherfile.json#/definitions/link
)。
JSON 文件是项目中的嵌入式资源。 rootpath
的变化取决于它的部署位置。但是在生产中一切正常(发出请求 JSON 响应与模式一样获得,当验证针对模式的响应时 NJsonSchema 在内部获取参考模式并提取完成验证所需的内容)
然而,如果涉及到测试,那就是另一回事了。响应很好,第一个模式被删除。 rootpath
是这样的,一切都与 http://testapi/
相关,但这实际上并不存在。因此,当 NJsonSchema 尝试获取参考架构时,它会查找类似 http://testapi/otherfile.json#/definitions/link
的内容,这显然失败了。
从阅读 this 我想我想使用重载来获取允许我指定 JsonReferenceResolver 的 JsonSchema4
对象,然后我可以在生产中使用默认值并注入我的拥有一个用于测试,以便它在我控制并将存在的某个地方寻找 $ref
s。但是我看不到这方面的任何文档或示例。
示例模式:
{ // root.json
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "@Model.Root/schemas/root.json",
"title": "Root",
"properties": {
"link": { "$ref": "@Model.Root/schemas/common.json#/definitions/link" }
},
"required": [ "link" ]
}
{ // common.json - different file to the above
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "@Model.Root/schemas/common.json",
"definitions": {
"link": {
"title": "Link",
"type": "object",
"properties": {
"rel": { "type": "string" },
"href": { "type": "string" }
},
"required": [ "rel", "href" ]
}
}
}
示例响应:
{
"schema": "http://testapi/schemas/root.json",
"link": { "rel": "self", "href": "http://testapi/root" }
};
验证码(C#):
using NJsonSchema;
using NJsonSchema.Validation;
...
JsonSchema4 schema = await JsonSchema4.FromJsonAsync(<contents of root.json file>);
string response = "{ ""link"": { ""rel"": ""self"", ""href"": ""http://testapi/root"" } }";
ICollection<ValidationError> errors = schema.Validate(response);
...
我指定 JsonReferenceResolver 的直觉是正确的。在上面的示例中,我无法在测试环境中从 root.json 到 'work' 获得对 common.json 的引用,因为在该环境中 service/path 不存在。
所以在设置环境时我确实知道 common.json 是什么,即我知道它的内容是一个字符串,因此可以将它作为一个模式 (JsonSchema4 commonSchema = JsonSchema4.FromJsonAsync(commonJsonAsString).Result;
)。
使用它我可以设置一个 'Reference Resolver Factory' 并在其中添加一个文档引用,以便从我的 commonSchema
获得对 http://testapi/schemas/common.json#/...
的所有引用,即
private Func<JsonSchema4, JsonReferenceResolver> referenceResolverFactory;
this.referenceResolverFactory = x =>
{
JsonSchemaResolver schemaResolver = new JsonSchemaResolver(x, new JsonSchemaGeneratorSettings());
JsonReferenceResolver referenceResolver = new JsonReferenceResolver(schemaResolver);
referenceResolver.AddDocumentReference("http://testapi/schemas/common.json", commonSchema);
return referenceResolver;
};
不同的引用可以通过同样的方式添加更多的文档引用来解决。
然后,当我尝试转换 root.json 模式(它引用 common.json)或另一个模式(引用 common.json)时,我使用 [=15= 的重载] 传入 referenceResolverFactory
:
private bool GetAndValidateResponse(string schemaName, string response, string schemaAsString)
{
// schemaName: Name of the schema being validated, e.g. "root.json"
// response: http response body as a string, see 'Example response' in question
// schemaAsString: The schema being validate as a string, e.g. root.json contents in question
//
// Check the response object against the schema
JsonSchema4 schema = JsonSchema4.FromJsonAsync(schemaAsString, schemaName, this.referenceResolverFactory).Result;
ICollection<ValidationError> errors = schema.Validate(response);
return errors.Count < 1;
}
在我的单元测试案例中,我只对它是否有效感兴趣,因此布尔值 return。如果您对确切的错误感兴趣,显然您可以 return 集合。
此外,我只为每个单元测试设置一次工厂 class,而不是为每个测试设置一次。但是,对于模式中的每个 ref
,它正确地进入每个工厂。
我已将我的 JSON 架构拆分为多个文件,并根据需要以标准方式引用它们 ("$ref": http://rootpath/otherfile.json#/definitions/link
)。
JSON 文件是项目中的嵌入式资源。 rootpath
的变化取决于它的部署位置。但是在生产中一切正常(发出请求 JSON 响应与模式一样获得,当验证针对模式的响应时 NJsonSchema 在内部获取参考模式并提取完成验证所需的内容)
然而,如果涉及到测试,那就是另一回事了。响应很好,第一个模式被删除。 rootpath
是这样的,一切都与 http://testapi/
相关,但这实际上并不存在。因此,当 NJsonSchema 尝试获取参考架构时,它会查找类似 http://testapi/otherfile.json#/definitions/link
的内容,这显然失败了。
从阅读 this 我想我想使用重载来获取允许我指定 JsonReferenceResolver 的 JsonSchema4
对象,然后我可以在生产中使用默认值并注入我的拥有一个用于测试,以便它在我控制并将存在的某个地方寻找 $ref
s。但是我看不到这方面的任何文档或示例。
示例模式:
{ // root.json
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "@Model.Root/schemas/root.json",
"title": "Root",
"properties": {
"link": { "$ref": "@Model.Root/schemas/common.json#/definitions/link" }
},
"required": [ "link" ]
}
{ // common.json - different file to the above
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "@Model.Root/schemas/common.json",
"definitions": {
"link": {
"title": "Link",
"type": "object",
"properties": {
"rel": { "type": "string" },
"href": { "type": "string" }
},
"required": [ "rel", "href" ]
}
}
}
示例响应:
{
"schema": "http://testapi/schemas/root.json",
"link": { "rel": "self", "href": "http://testapi/root" }
};
验证码(C#):
using NJsonSchema;
using NJsonSchema.Validation;
...
JsonSchema4 schema = await JsonSchema4.FromJsonAsync(<contents of root.json file>);
string response = "{ ""link"": { ""rel"": ""self"", ""href"": ""http://testapi/root"" } }";
ICollection<ValidationError> errors = schema.Validate(response);
...
我指定 JsonReferenceResolver 的直觉是正确的。在上面的示例中,我无法在测试环境中从 root.json 到 'work' 获得对 common.json 的引用,因为在该环境中 service/path 不存在。
所以在设置环境时我确实知道 common.json 是什么,即我知道它的内容是一个字符串,因此可以将它作为一个模式 (JsonSchema4 commonSchema = JsonSchema4.FromJsonAsync(commonJsonAsString).Result;
)。
使用它我可以设置一个 'Reference Resolver Factory' 并在其中添加一个文档引用,以便从我的 commonSchema
获得对 http://testapi/schemas/common.json#/...
的所有引用,即
private Func<JsonSchema4, JsonReferenceResolver> referenceResolverFactory;
this.referenceResolverFactory = x =>
{
JsonSchemaResolver schemaResolver = new JsonSchemaResolver(x, new JsonSchemaGeneratorSettings());
JsonReferenceResolver referenceResolver = new JsonReferenceResolver(schemaResolver);
referenceResolver.AddDocumentReference("http://testapi/schemas/common.json", commonSchema);
return referenceResolver;
};
不同的引用可以通过同样的方式添加更多的文档引用来解决。
然后,当我尝试转换 root.json 模式(它引用 common.json)或另一个模式(引用 common.json)时,我使用 [=15= 的重载] 传入 referenceResolverFactory
:
private bool GetAndValidateResponse(string schemaName, string response, string schemaAsString)
{
// schemaName: Name of the schema being validated, e.g. "root.json"
// response: http response body as a string, see 'Example response' in question
// schemaAsString: The schema being validate as a string, e.g. root.json contents in question
//
// Check the response object against the schema
JsonSchema4 schema = JsonSchema4.FromJsonAsync(schemaAsString, schemaName, this.referenceResolverFactory).Result;
ICollection<ValidationError> errors = schema.Validate(response);
return errors.Count < 1;
}
在我的单元测试案例中,我只对它是否有效感兴趣,因此布尔值 return。如果您对确切的错误感兴趣,显然您可以 return 集合。
此外,我只为每个单元测试设置一次工厂 class,而不是为每个测试设置一次。但是,对于模式中的每个 ref
,它正确地进入每个工厂。