10分钟理解契约测试及如何在C#中实现

2025-12-13 0 825

在软件开发中,确保微服务和API的可靠性和稳定性非常重要。 随着应用程序变得越来越复杂,对强大的测试策略的需求也越来越大,这些策略可以帮助团队在不牺牲敏捷性的情况下交付高质量的代码。 近年来获得广泛关注的一种方法是契约测试(Contract Testing)。 在本文中,我将揭开契约测试的神秘面纱,并向您展示如何在 C# 项目中实现它。

1. 术语

消费者(Consumer:对服务进行消费的代码,通常指的是客户端。

提供者(Provider:提供服务的代码,通常指的是服务器端。

契约(Contract:消费者和提供者之间商定的协议。 它包括预期的请求(输入)和响应(输出)。

2. 为什么需要契约测试?

构建和维护微服务是一项艰巨的任务。 在众多服务必须彼此无缝交互的世界中,确保对一项服务的更改不会破坏另一项服务的功能是很让人头疼的。 传统的集成测试针对的是整个系统之间的交互,工作量太大、速度太慢,甚至无法直接识别问题。 与之相反的是,契约测试侧重于测试各个服务之间的契约。 合同测试根据消费者和提供商之间商定的契约分别对消费者和提供商进行测试。

3. 如何执行契约测试

在契约测试中,消费者端程序员编写“消费者测试”,其中包含期望的输入和输出,并且期望将被保存到 Pact Json 文件中。 运行时,测试将请求发送到内置的模拟服务器而不是真实服务器,模拟服务器使用保存的 Pact Json 文件发送响应,该响应将用于验证消费者端测试用例。

此外,契约测试框架将读取保存的 Pact Json 文件,并向服务提供者(服务器)发送请求,并且将根据 Pact Json 文件中的预期输出来验证响应。

4. What is Pact?

Pact 是合约测试的实现。 由于消费者和提供者可能使用不同的编程语言进行开发,因此 Pact 是语言无关的,它支持多种编程语言,例如 Java、.NET、Ruby、JavaScript、Python、PHP 等。保存的 Pact Json 文件是由 用一种编程语言开发的消费者可以用来验证用另一种编程语言开发的提供者。

在本文中,消费者和提供者都是使用.NET (C#) 开发的。 Pact.Net 是 Pact 在 .Net 中的实现。

5. 如何使用Pact.Net?

使用Pact.Net总共分三步:开发一个待测试的WebAPI服务;编写消费者端测试用例;编写提供者端测试用例。

a. 开发待测试的WebAPI服务

创建一个 ASP.Net Core WebAPI项目,然后如下编写一个简单的控制器。

[ApiController]
[Route(\”[controller]/[action]\”)]
public class MyController : ControllerBase
{
[HttpGet]
public int Abs(int i)
{
return Math.Abs(i);
}
}

上面的控制器提供了一个计算给定整数的绝对值的简单服务。

Pact需要使用ASP.Net Core项目的Startup类来启动Web服务器,但是,在最新的.NET Core中,传统的Startup.cs被Minimal API取代。如果 要将 Pact 与 .NET Core 一起使用,您必须切换到 传统Startup 风格的代码,如果您不知道如何切换回传统的Startup 风格的代码,请 搜索“Adding Back the Startup Class to ASP.NET Core”。

b. 编写消费者端测试用例

创建一个使用xUnit的.NET测试项目,然后在测试项目上安装“PactNet”这个Nuget包。然后编写如下的测试用例。

public class UnitTest1
{
private readonly IPactBuilderV4 pactBuilder;
public UnitTest1()
{
var pact = Pact.V4(\”MyAPI consumer\”, \”MyAPI\”,new PactConfig());
this.pactBuilder = pact.WithHttpInteractions();
}
[Fact]
public async Task Test1()
{
this.pactBuilder.UponReceiving(\”A request to calc Abs\”)
.Given(\”Abs\”)
.WithRequest(HttpMethod.Get, \”/My/Abs\”)
.WithQuery(\”i\”,\”-2\”)//Match.Integer(-2)
.WillRespond()
.WithStatus(HttpStatusCode.OK)
.WithJsonBody(2);

await this.pactBuilder.VerifyAsync(async ctx=>
{
using HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = ctx.MockServerUri;
var r = await httpClient.GetFromJsonAsync<int>($\”/My/Abs?i=-2\”);
Assert.Equal(2,r);
});
}
}

“WithRequest().WithQuery()”用于定义输入,“WillRespond().WithJsonBody()”用于定义相应的预期输出。VerifyAsync中的代码片段是测试用例,根据“UponReceiving”定义的期望进行测试。 从“httpClient.BaseAddress = ctx.MockServerUri”可以看出,Provider 测试用例与 Pact 提供的Mock服务器交互而不是真实服务器进行交互。

接下来,让我们运行测试,测试运行完成后,测试项目的pact文件夹下会生成一个“MyAPI Consumer-MyAPI.json”,这个Json文件中保存了预期的输入和输出,如下图。

10分钟理解契约测试及如何在C#中实现10分钟理解契约测试及如何在C#中实现

c. 编写提供者端测试用例

创建一个使用xUnit的.NET测试项目,然后向其安装 Nuget 包“PactNet”和“PactNet.Output.Xunit”。 由于提供程序测试必须使用 Startup 类启动测试服务器,因此请将待测试的 ASP.NET Core WebAPI 项目的引用添加到提供程序测试项目中。

创建一个“MyApiFixture”类,用于启动测试项目中测试的WebAPI服务器。MyApiFixture类的代码如下:

public class MyApiFixture: IDisposable
{
private readonly IHost server;
public Uri ServerUri { get; }
public MyApiFixture()
{
ServerUri = new Uri(\”http://localhost:9223\”);
server = Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseUrls(ServerUri.ToString());
webBuilder.UseStartup<Startup>();
})
.Build();
server.Start();
}

public void Dispose()
{
server.Dispose();
}
}

接下来,如下创建一个使用保存的Pact Json文件对服务器(提供者)进行测试的测试用例。

public class MyApiTest1: IClassFixture<MyApiFixture>
{
private readonly MyApiFixture fixture;
private readonly ITestOutputHelper output;
public MyApiTest1(MyApiFixture fixture,ITestOutputHelper output)
{
this.fixture = fixture;
this.output = output;
}
[Fact]
public async Task Test1()
{
var config = new PactVerifierConfig
{
Outputters = new List<IOutput>
{
new XunitOutput(output),
},
};
string pactPath = Path.Combine(\”..\”,\”..\”,\”..\”,\”..\”,
\”TestConsumerProject1\”, \”pacts\”, \”MyAPI consumer-MyAPI.json\”);
using var pactVerifier = new PactVerifier(\”MyAPI\”, config);
pactVerifier
.WithHttpEndpoint(fixture.ServerUri)
.WithFileSource(new FileInfo(pactPath))
.Verify();
}
}

“pactPath”是指保存的Pact文件,在您的项目中,它会根据项目名称、相对路径的不同而不同。 执行上述测试时,Pact 将启动测试项目中的测试服务器,发送请求并根据保存的 Json 文件验证响应。

6. 对基于消息的服务使用Pact

Pact也支持对于基于消息的服务(也被称为async API)进行测试。详细请查看Pact文档的“messaging pacts”部分。

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

申明:本文由第三方发布,内容仅代表作者观点,与本网站无关。对本文以及其中全部或者部分内容的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。本网发布或转载文章出于传递更多信息之目的,并不意味着赞同其观点或证实其描述,也不代表本网对其真实性负责。

左子网 编程相关 10分钟理解契约测试及如何在C#中实现 https://www.zuozi.net/36417.html

常见问题
  • 1、自动:拍下后,点击(下载)链接即可下载;2、手动:拍下后,联系卖家发放即可或者联系官方找开发者发货。
查看详情
  • 1、源码默认交易周期:手动发货商品为1-3天,并且用户付款金额将会进入平台担保直到交易完成或者3-7天即可发放,如遇纠纷无限期延长收款金额直至纠纷解决或者退款!;
查看详情
  • 1、描述:源码描述(含标题)与实际源码不一致的(例:货不对板); 2、演示:有演示站时,与实际源码小于95%一致的(但描述中有”不保证完全一样、有变化的可能性”类似显著声明的除外); 3、发货:不发货可无理由退款; 4、安装:免费提供安装服务的源码但卖家不履行的; 5、收费:价格虚标,额外收取其他费用的(但描述中有显著声明或双方交易前有商定的除外); 6、其他:如质量方面的硬性常规问题BUG等。 注:经核实符合上述任一,均支持退款,但卖家予以积极解决问题则除外。
查看详情
  • 1、左子会对双方交易的过程及交易商品的快照进行永久存档,以确保交易的真实、有效、安全! 2、左子无法对如“永久包更新”、“永久技术支持”等类似交易之后的商家承诺做担保,请买家自行鉴别; 3、在源码同时有网站演示与图片演示,且站演与图演不一致时,默认按图演作为纠纷评判依据(特别声明或有商定除外); 4、在没有”无任何正当退款依据”的前提下,商品写有”一旦售出,概不支持退款”等类似的声明,视为无效声明; 5、在未拍下前,双方在QQ上所商定的交易内容,亦可成为纠纷评判依据(商定与描述冲突时,商定为准); 6、因聊天记录可作为纠纷评判依据,故双方联系时,只与对方在左子上所留的QQ、手机号沟通,以防对方不承认自我承诺。 7、虽然交易产生纠纷的几率很小,但一定要保留如聊天记录、手机短信等这样的重要信息,以防产生纠纷时便于左子介入快速处理。
查看详情

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务