You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C# Pact测试中使用Like或SomethingLike?

Pact测试中验证JSON响应Schema的实现方法

问题背景

我写的第一个Pact测试仅验证响应为200 OK,现在希望添加测试来验证JSON响应的Schema。了解到like或SomethingLike是解决方案,但不清楚在测试代码中的使用位置(详见代码内最后一条注释)。

原测试代码:

var pact = Pact.V4("WidgetsApiConsumer", "WidgetsApi", new PactConfig { LogLevel = PactLogLevel.Debug });

var pactBuilder = pact.WithHttpInteractions();
pactBuilder
   .UponReceiving("A GET request to retrieve widgets")
   .Given("There is more than one widget")
   .WithRequest(HttpMethod.Get, "/Widgets")
   .WillRespond()
   .WithStatus(HttpStatusCode.OK)
   .WithHeader("Content-Type", "application/json; charset=utf-8")
   .WithJsonBody(new[] {
   new
   {
      id = "B9CE5196-72F8-4FD7-B7CC-405FF62E8793",
      description = "Widget No.1"
   },
   new
   {
      id = "7F236BA3-D0D1-47F1-B379-71A3ABD46302",
      description = "Widget No.2"
   },
   });

await pactBuilder.VerifyAsync(async ctx =>
{
   var client = new HttpClient { BaseAddress = ctx.MockServerUri };
   var response = await client.GetAsync("/Widgets");

   response.Should().NotBeNull();
   response.IsSuccessStatusCode.Should().BeTrue();

   // 验证JSON schema
   var responseBody = await response.Content.ReadAsStringAsync();
   var widgetsContainer = JsonSerializer.Deserialize<WidgetsContainer>(responseBody, JsonSerializerOptions.Web);
   widgetsContainer.Should().NotBeNull();
   var widgets = widgetsContainer.Widgets;
   widgets.Should().NotBeNull();
   widgets.Count.Should().Be(2);
   // 断言ID是有效的GUID,不一定是"B9CE5196-72F8-4FD7-B7CC-405FF62E8793"
   // 我该如何在Pact JSON中定义这个?
   widgets[0].Id.Should().NotBeEmpty();
...

解决方法

核心是在定义Pact响应的JSON Body阶段使用SomethingLike(.NET Pact库内置匹配器),替代写死的具体值,让Pact生成Schema规则来验证响应的结构和类型,而非匹配固定内容。

修改后的代码示例

var pact = Pact.V4("WidgetsApiConsumer", "WidgetsApi", new PactConfig { LogLevel = PactLogLevel.Debug });

var pactBuilder = pact.WithHttpInteractions();
pactBuilder
   .UponReceiving("A GET request to retrieve widgets")
   .Given("There is more than one widget")
   .WithRequest(HttpMethod.Get, "/Widgets")
   .WillRespond()
   .WithStatus(HttpStatusCode.OK)
   .WithHeader("Content-Type", "application/json; charset=utf-8")
   .WithJsonBody(new[] {
      new
      {
         // 用SomethingLike指定类型为GUID,不限制具体值
         id = Match.SomethingLike(Guid.NewGuid()),
         description = Match.SomethingLike("Widget No.1")
      },
      new
      {
         id = Match.SomethingLike(Guid.NewGuid()),
         description = Match.SomethingLike("Widget No.2")
      },
   });

await pactBuilder.VerifyAsync(async ctx =>
{
   var client = new HttpClient { BaseAddress = ctx.MockServerUri };
   var response = await client.GetAsync("/Widgets");

   response.Should().NotBeNull();
   response.IsSuccessStatusCode.Should().BeTrue();

   var responseBody = await response.Content.ReadAsStringAsync();
   var widgetsContainer = JsonSerializer.Deserialize<WidgetsContainer>(responseBody, JsonSerializerOptions.Web);
   widgetsContainer.Should().NotBeNull();
   var widgets = widgetsContainer.Widgets;
   widgets.Should().NotBeNull();
   widgets.Count.Should().Be(2);
   // 直接验证ID为有效GUID类型
   widgets[0].Id.Should().BeOfType<Guid>();
   widgets[1].Id.Should().BeOfType<Guid>();
});

关键说明

  • Match.SomethingLike()的作用是告诉Pact:只要响应字段的类型与示例值一致(如GUID、字符串),就算验证通过,无需匹配具体内容。
  • 若需更严格的格式验证,比如确保ID符合GUID正则规则,可改用Match.Regex():
    id = Match.Regex(Guid.NewGuid().ToString(), @"^[0-9A-F]{8}-[0-9A-F]{4}-[4][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$")
    
  • 使用匹配器定义响应Body后,Pact生成的契约文件会包含Schema验证规则,后续消费者与提供者的契约校验会自动检查响应结构和类型是否合规。

内容的提问来源于stack exchange,提问作者Bernhard Hofmann

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 03:14:56