如何断言 API 响应具有特定结构?
How to assert that a API response has a specific structure?
我设置了一个 SpecFlow 测试定义,我想断言该响应在其响应中具有特定的字段集合。例如,我有来自 API:
的特殊预期响应
{
isActive: false,
lastProcessed: "2020-11-03T19:03:16.537"
}
我要验证的是响应包含这两个字段,不一定是这些字段包含的值。我尝试了以下方法:
Assert.NotNull(response.Model.isActive);
Assert.NotNull(response.Model.lastProcessed);
但我在使用此方法时遇到错误:
Do not use Assert.NotNull() on value type 'bool'
除了使用“NotNull()”之外,我还能如何确保响应结构符合预期?
解决方案:
按照接受的答案,我将从 API 调用返回的模型序列化为 JSON 并将其解析为 JObject。然后我使用 ContainsKey() 方法断言它。
JObject jObject = JObject.Parse(JsonConvert.SerializeObject(response.Model));
Assert.True(jObject.ContainsKey("isActive"));
我不知道你使用什么包来发送请求和反序列化,但如果你可以将响应内容作为原始 json 字符串获取,那么你可以使用 Newtonsoft.JSON 将响应解析为JObject
和 JObject.Parse(responseContent)
。 JObject
有个方法叫ContainsKey(propertyName)
,判断对象中是否有指定名称的字段。您可以断言如果它 returns 对于所需的 属性 名称为真。
编辑
关于下面 Greg 的回答。原始错误实际上是由 bool
不是可空类型引起的,在模型中使其可为空可以修复错误。然而,这个解决方案并不理想。在某些情况下,null
可能是 API 返回的有效值,这会产生漏报。例如如果我们收到:
{
isActive: null,
lastProcessed: "2020-11-03T19:03:16.537"
}
那么 Assert.NotNull(response.Model.isActive)
会产生一个否定的测试结果,即使该字段存在于 json 中,这就是我们想要检查的内容。
所以理论上,如果我们 100% 确定 null
永远不会被 API 本身返回,那么我们可以那样做,但它不会是一个通用的方法。也没有很好地描述我们正在努力实现的目标 ;)
因为 isActive
属性 是一个 bool
你需要断言它是假的。相反,如果您想要一个 true 或 false 值,然后用一些东西来表示它丢失了,请在您的 DTO 中使用可为 null 的布尔值:
public class YourDTO
{
public bool? isActive { get; set; }
...
}
然后您可以断言 isActive
为 null、true 或 false。
备选方案: 如果您无法更新原始数据传输对象,那么这可能是编写您自己的代码来调用 Web 服务并映射 JSON 对您自己的仅用于测试的 DTO 的响应。
但是,这可能是一项大量的工作。优点是您的测试代码与它测试的代码真正分离。我也对使用数据库的应用程序完成了此操作。这是额外的工作,但它允许您的测试使用对测试有意义的任何数据结构。
我设置了一个 SpecFlow 测试定义,我想断言该响应在其响应中具有特定的字段集合。例如,我有来自 API:
的特殊预期响应{
isActive: false,
lastProcessed: "2020-11-03T19:03:16.537"
}
我要验证的是响应包含这两个字段,不一定是这些字段包含的值。我尝试了以下方法:
Assert.NotNull(response.Model.isActive);
Assert.NotNull(response.Model.lastProcessed);
但我在使用此方法时遇到错误:
Do not use Assert.NotNull() on value type 'bool'
除了使用“NotNull()”之外,我还能如何确保响应结构符合预期?
解决方案: 按照接受的答案,我将从 API 调用返回的模型序列化为 JSON 并将其解析为 JObject。然后我使用 ContainsKey() 方法断言它。
JObject jObject = JObject.Parse(JsonConvert.SerializeObject(response.Model));
Assert.True(jObject.ContainsKey("isActive"));
我不知道你使用什么包来发送请求和反序列化,但如果你可以将响应内容作为原始 json 字符串获取,那么你可以使用 Newtonsoft.JSON 将响应解析为JObject
和 JObject.Parse(responseContent)
。 JObject
有个方法叫ContainsKey(propertyName)
,判断对象中是否有指定名称的字段。您可以断言如果它 returns 对于所需的 属性 名称为真。
编辑
关于下面 Greg 的回答。原始错误实际上是由 bool
不是可空类型引起的,在模型中使其可为空可以修复错误。然而,这个解决方案并不理想。在某些情况下,null
可能是 API 返回的有效值,这会产生漏报。例如如果我们收到:
{
isActive: null,
lastProcessed: "2020-11-03T19:03:16.537"
}
那么 Assert.NotNull(response.Model.isActive)
会产生一个否定的测试结果,即使该字段存在于 json 中,这就是我们想要检查的内容。
所以理论上,如果我们 100% 确定 null
永远不会被 API 本身返回,那么我们可以那样做,但它不会是一个通用的方法。也没有很好地描述我们正在努力实现的目标 ;)
因为 isActive
属性 是一个 bool
你需要断言它是假的。相反,如果您想要一个 true 或 false 值,然后用一些东西来表示它丢失了,请在您的 DTO 中使用可为 null 的布尔值:
public class YourDTO
{
public bool? isActive { get; set; }
...
}
然后您可以断言 isActive
为 null、true 或 false。
备选方案: 如果您无法更新原始数据传输对象,那么这可能是编写您自己的代码来调用 Web 服务并映射 JSON 对您自己的仅用于测试的 DTO 的响应。
但是,这可能是一项大量的工作。优点是您的测试代码与它测试的代码真正分离。我也对使用数据库的应用程序完成了此操作。这是额外的工作,但它允许您的测试使用对测试有意义的任何数据结构。