实战指南:使用 xUnit 和 ASP.NET Core 进行集成测试【完整教程】

这篇具有很好参考价值的文章主要介绍了实战指南:使用 xUnit 和 ASP.NET Core 进行集成测试【完整教程】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

引言

集成测试可在包含应用支持基础结构(如数据库、文件系统和网络)的级别上确保应用组件功能正常。 ASP.NET Core 通过将单元测试框架与测试 Web 主机和内存中测试服务器结合使用来支持集成测试。

简介

集成测试与单元测试相比,能够在更广泛的级别上评估应用的组件,确认多个组件一起工作以生成预期结果,包括数据库、文件系统、网络设备等组件。单元测试主要用于测试独立软件组件,如类方法,通常使用 fakemock 对象。集成测试使用实际组件,需要更多代码和数据处理,运行时间更长。建议将集成测试限制在重要的基础结构方案上,若可用单元测试或集成测试测试行为,优先选择单元测试。集成测试中被测试的项目通常称为"SUT",用于指代要测试的应用。避免为每种数据库和文件系统交互排列编写集成测试,而是通过一组集中式读取、写入、更新和删除集成测试充分测试这些组件,使用单元测试测试与这些组件交互的方法逻辑,使用 fakemock 对象可加快测试速度。

集成测试实战

我们在之前的章节中创建了Sample.ApiSample.Repository的项目,现在我们对这个项目进行整体的集成测试,带大家来感受一下。

ASP.NET Core 中的集成测试需要以下内容:

  • 测试项目用于包含和执行测试。 测试项目具有对 SUT 的引用。
  • 测试项目为 SUT 创建测试Web主机,并使用测试服务器客户端处理 SUT 的请求和响应。
  • 测试运行程序用于执行测试并报告测试结果。

集成测试后跟一系列事件,包括常规“排列”“操作”“断言”测试步骤:

  • 已配置 SUTWeb 主机。
  • 创建测试服务器客户端以向应用提交请求。
  • 执行“排列”测试步骤:测试应用会准备请求。
  • 执行“操作”`测试步骤:客户端提交请求并接收响应。
  • 执行“断言”测试步骤:实际响应基于预期响应验证为通过或失败。
  • 该过程会一直继续,直到执行了所有测试。
  • 报告测试结果。

上面解释到了集成测试中被测试的项目通常称为SUT。我们要测试的项目Sample.Api既是我们的SUT

好了我们开始创建xUnit的单元测试项目,并添加Sample.Api的项目引用.

集成测试第一步

在我们的单元测试项目中安装Nuget依赖

PM> NuGet\Install-Package Microsoft.AspNetCore.Mvc.Testing -Version 8.0.4

基础结构组件(如测试 Web 主机和内存中测试服务器 (TestServer))由 Microsoft.AspNetCore.Mvc.Testing 包提供或管理。 使用此包可简化测试创建和执行。

Microsoft.AspNetCore.Mvc.Testing 包处理以下任务:

将依赖项文件 (.deps) 从 SUT 复制到测试项目的 bin目录中。
将内容根目录设置为 SUT 的项目根目录,以便可在执行测试时找到静态文件和页面/视图。
提供 WebApplicationFactory 类,以简化 SUTTestServer 中的启动过程。

概念有点多,后续里面的概念会慢慢讲到。

我们知道Asp.Net CoreWeb项目项目是借助Kestrel启动,用集成测试的TestServer正是代替了Kestrel托管服务的启动,那我们要测试的项目就不需要单独被启动了。

什么是TestServer?

TestServer 用于在集成测试中模拟和启动应用程序的主机环境。通过创建 TestServer 实例,可以在测试中模拟出一个运行中的应用程序实例,以便进行端到端的集成测试。

Microsoft.AspNetCore.Mvc.Testing中已经默认集成了对TestServer的支持所以,不需要额外进行配置。

SUT 环境?

如果未设置 SUT 的环境,则环境会默认为开发环境即 Development

向测试项目公开启动类Program

使用 WebApplicationFactory<TEntryPoint> 创建 TestServer以进行集成测试。 TEntryPointSUT 的入口点类,通常是 Program.cs

有两种向测试项目公开 Program 的方法

  • Program.cs添加部分类
  var builder = WebApplication.CreateBuilder(args);
  // ... Configure services, routes, etc.
  app.Run();
  + public partial class Program { }
  • 配置MSBuild
    SUTcsproj文件下添加
	<ItemGroup>
		<Using Include="Sample.Api" />
		<InternalsVisibleTo Include="dotNetParadise.IntegrationTest" />
	</ItemGroup>
  1. <Using Include="Sample.Api" />:这个子元素指定了要在项目中使用的命名空间或程序集。在这里,Sample.Api 被包含在项目中,以便项目可以访问和使用该命名空间或程序集中的内容。

  2. <InternalsVisibleTo Include="dotNetParadise.IntegrationTest" />:这个子元素用于将内部可见性(InternalsVisibleTo)属性应用于项目,允许指定的程序集(在这里是 dotNetParadise.IntegrationTest)访问项目中的内部成员。这在单元测试或集成测试中非常有用,因为测试项目通常需要访问被测试项目的内部成员以进行更全面的测试。

相对来说更推荐使用第一种部分类的形式来对测试项目公开。

WebApplicationFactory

可以使用默认的WebApplicationFactory和自定义的WebApplicationFactory来进行集成测试

测试类实现一个类固定例程接口 (IClassFixture),以指示类包含测试,并在类中的所有测试间提供共享对象实例。

来感受一下

使用默认 WebApplicationFactory 的基本测试

看一下如何使用

public class DefaultWebApplicationFactoryTest : IClassFixture<WebApplicationFactory<Program>>
{
    private readonly WebApplicationFactory<Program> _factory;

    public DefaultWebApplicationFactoryTest(WebApplicationFactory<Program> factory)
    {
        _factory = factory;
    }

    [Fact]
    public async Task GetAll_Query_ReturnOkAndListStaff()
    {
        //Arrange
        var httpClient = _factory.CreateClient();
        //act
        var response = await httpClient.GetAsync("/api/Staff");
        //Assert
        //校验状态码
        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        //校验用户
        var users = await response.Content.ReadFromJsonAsync<List<Staff>>();
        Assert.NotNull(users);
    }

    [Fact]
    public async Task GetConfig_WhenCalled_ReturnOk() {
        //Arrange
        var httpClient = _factory.CreateClient();
        //act
        var response = await httpClient.GetAsync("/GetConfig");
        //Assert
        //校验状态码
        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        //校验用户
        var config = await response.Content.ReadFromJsonAsync<string>();
        Assert.NotNull(config);
    }
}

看到我们的测试类继承了IClassFixture来共享实例对象,并且泛型类型是默认的WebApplicationFactory<Program>

接下来在我们的SUTSample.Apiprogram中打个断点来验证一下

实战指南:使用 xUnit 和 ASP.NET Core 进行集成测试【完整教程】

看到了我们测试时默认的 WebApplicationFactory 使用默认配置启动应用程序主机,包括加载 appsettings.json 等配置文件。

在我们的appsettings.Development.json中加了一个配置

{
  "Config": "这里是appsettings.Development.json"
}

GetConfig_WhenCalled_ReturnOk 测试方法看下结果

实战指南:使用 xUnit 和 ASP.NET Core 进行集成测试【完整教程】

正确的读到appsettings.Development.json的内容了,从而可以得出我们上面的结论,如果未设置 SUT 的环境,则环境会默认为开发环境即 Development

从上面我们看到我们向SUT发请求是调用的CreateClient()
CreateClient() 方法用于创建一个 HttpClient 实例,用于模拟客户端与 SUT 进行交互。通过这个 HttpClient,测试代码可以发送 HTTP 请求到应用程序,并验证应用程序的响应。

总的来说默认的 WebApplicationFactory 提供了一种快速启动应用程序主机进行集成测试的方式,适用于简单的测试场景。

自定义 WebApplicationFactory

通过从 WebApplicationFactory<TEntryPoint> 来创建一个或多个自定义工厂,可以独立于测试类创建 Web 主机配置

我们来创建一个SampleApiWebAppFactory的类,然后继承WebApplicationFactory<Program>

public class SampleApiWebAppFactory : WebApplicationFactory<Program>
{
    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {

        builder.ConfigureServices((context, services) =>
        {

        });
        builder.UseEnvironment("Production");
        base.ConfigureWebHost(builder);
    }

    public HttpClient Client()
    {
        return CreateDefaultClient();
    }
}

实战指南:使用 xUnit 和 ASP.NET Core 进行集成测试【完整教程】

里面有Asp.Net Core 启动项配置,我们都可以在自定义的SampleApiWebAppFactory进行重写, 自定义的 WebApplicationFactory 提供了一种灵活的方式来定制化应用程序主机的配置,并扩展功能以满足特定的测试需求。通过继承并重写 ConfigureWebHost 方法等,开发人员可以对应用程序主机进行自定义配置,包括添加新的服务、中间件或修改默认配置,从而在测试环境中模拟特定的场景或功能。

优势和功能扩展:

  • 定制化配置: 自定义的 WebApplicationFactory 允许开发人员根据测试需求添加自定义配置,比如测试环境特定的服务、中间件或其他设置,以确保测试环境与实际生产环境保持一致或满足特定测试需求。
  • 功能扩展: 通过重写 ConfigureWebHost 方法,开发人员可以扩展应用程序主机的功能,例如注册额外的服务、修改中间件管道、添加测试专用的配置等,从而更好地适应测试场景。

复杂性和维护:

  • 定制化代码量增加: 自定义的 WebApplicationFactory 可能会包含更多的定制化代码,需要更多的理解和维护,但这样可以更好地控制应用程序主机的配置和功能。
  • 更高的灵活性: 虽然需要更多的理解和维护,但自定义的 WebApplicationFactory 提供了更大的灵活性和定制性,可以满足更复杂的测试需求,并确保测试环境的准确性和一致性。

总的来说,通过自定义的 WebApplicationFactory,开发人员可以根据具体的测试场景和需求定制化配置和功能,以确保在集成测试中能够模拟真实的应用程序环境,并进行更全面和准确的测试。这种方式允许开发人员更好地控制应用程序主机的设置,以适应不同的测试需求和场景。

SUT 的数据库上下文在 Program.cs 中注册。 测试应用的 builder.ConfigureServices 回调在执行应用的 Program.cs 代码之后执行。 若要将与应用数据库不同的数据库用于测试,必须在 builder.ConfigureServices 中替换应用的数据库上下文。

builder.ConfigureServices((context, services) =>
{
    var descriptor = new ServiceDescriptor(
        typeof(DbContextOptions<SampleDbContext>),
        serviceProvider => DbContextFactory<SampleDbContext>(serviceProvider, (sp, o) =>
        {
            o.UseInMemoryDatabase("TestDB");
        }),
         ServiceLifetime.Scoped);

    services.Replace(descriptor);
});

上面用到的DbContextFactory方法

    private static DbContextOptions<TContext> DbContextFactory<TContext>(IServiceProvider applicationServiceProvider,
      Action<IServiceProvider, DbContextOptionsBuilder> optionsAction)
      where TContext : DbContext
    {
        var builder = new DbContextOptionsBuilder<TContext>(
            new DbContextOptions<TContext>(new Dictionary<Type, IDbContextOptionsExtension>()));

        builder.UseApplicationServiceProvider(applicationServiceProvider);

        optionsAction?.Invoke(applicationServiceProvider, builder);

        return builder.Options;
    }

来写个集成测试

public class SampleApiTest(SampleApiWebAppFactory factory) : IClassFixture<SampleApiWebAppFactory>
{

    [Fact]
    public async Task GetAll_Query_ReturnOkAndListStaff()
    {
        //Arrange
        var httpClient = factory.CreateClient();
        //act
        var response = await httpClient.GetAsync("/api/Staff");
        //Assert
        //校验状态码
        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        //校验用户
        var users = await response.Content.ReadFromJsonAsync<List<Staff>>();
        Assert.NotNull(users);
    }

    [Fact]
    public async Task GetConfig_WhenCalled_ReturnOk()
    {
        //Arrange
        var httpClient = factory.CreateClient();
        //act
        var response = await httpClient.GetAsync("/GetConfig");
        //Assert
        //校验状态码
        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        //校验用户
        var config = await response.Content.ReadFromJsonAsync<string>();
        Assert.NotNull(config);
    }

    // 后面测试省略。。。。
}

实战指南:使用 xUnit 和 ASP.NET Core 进行集成测试【完整教程】

最后

集成测试是确保应用组件在包含数据库、文件系统和网络等基础结构的级别上正常运行的重要方式。ASP.NET Core通过结合单元测试框架、测试Web主机和内存中测试服务器来支持集成测试。

在集成测试中,我们评估应用组件在更广泛的级别上的功能,验证多个组件一起工作以生成预期结果,包括数据库、文件系统、网络设备等。单元测试主要用于测试独立的软件组件,而集成测试需要使用实际组件,涉及更多的代码和数据处理,以及更长的运行时间。建议将集成测试限制在重要的基础结构方案上,优先选择单元测试或集成测试来测试行为。

在集成测试中,被测试的项目通常称为SUTSystem Under Test),用于指代要测试的应用。避免为每种数据库和文件系统交互编写独立的集成测试,而是通过一组集中式的测试来全面测试这些组件,并使用单元测试来测试与这些组件交互的方法逻辑。

通过自定义的WebApplicationFactory,可以根据测试需求定制化配置和功能,模拟真实的应用程序环境进行全面和准确的测试。自定义的WebApplicationFactory提供了灵活性和定制性,满足复杂的测试需求,并确保测试环境的准确性。虽然自定义的WebApplicationFactory可能需要更多的理解和维护,但能更好地适应不同的测试场景。

集成测试是确保应用程序正常运行的关键步骤,通过综合不同组件的功能来验证应用的整体表现,提高应用程序的质量和稳定性。文章来源地址https://www.toymoban.com/news/detail-855015.html

  • ASP.NET Core 中的集成测试
  • 本文完整源代码

到了这里,关于实战指南:使用 xUnit 和 ASP.NET Core 进行集成测试【完整教程】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ASP.NET Core 中使用 WebSocket 协议进行实时通信

    介绍 在 ASP.NET Core 中使用 WebSocket 协议创建实时通信的完整示例涉及几个步骤。在此示例中,我们将创建一个简单的聊天应用程序,用户可以在其中实时发送和接收消息。此示例假设您对 ASP.NET Core 和 C# 有基本了解。 步骤1.创建一个新的ASP.NET Core项目 首先,使用 Visual Studio 或

    2024年01月25日
    浏览(51)
  • 在ASP.NET Core中轻松使用JwtBeare进行身份验证

    JwtBearer简介 首先要搞清楚什么是JwtBearer,JwtBearer是ASP.NET Core的OAuth 2.0 JWT Bearer身份验证提供程序。它提供了对JWT令牌进行验证的功能,然后允许将令牌中包含的声明(claims)用于用户身份验证和授权控制。 Json Web Token (JWT)是一种Web标准,用于在不同系统间传输数据。JWT是一种

    2024年02月04日
    浏览(50)
  • 使用 Asp.net core webapi 集成配置系统,提高程序的灵活和可维护性

    集成配置系统的主要目的是将应用程序的配置信息与代码分离,使得配置信息可以在不需要修改代码的情况下进行更改。这样可以提高应用程序的灵活性和可维护性。 ASP.NET Core 提供了一种灵活的配置系统,可以轻松地将配置信息从不同的来源加载到应用程序中,并且可以根

    2024年02月01日
    浏览(67)
  • Asp .Net Core 系列: 集成 CORS跨域配置

    CORS,全称是“跨源资源共享”(Cross-Origin Resource Sharing),是一种Web应用程序的安全机制,用于控制不同源的资源之间的交互。 在Web应用程序中,CORS定义了一种机制,通过该机制,浏览器能够限制哪些外部网页可以访问来自不同源的资源。源由协议、域名和端口组成。当一

    2024年01月24日
    浏览(88)
  • Asp .Net Core 系列: 集成 Consul 实现 服务注册与健康检查

    官网:https://www.consul.io/ Consul 是一款开源的服务发现和配置管理工具,它能够监控应用程序和服务之间的通信,并提供了一组 API 和 Web UI,用于管理服务和配置。 Consul 是分布式的、高可用的、可横向扩展的,具备以下特性: 服务发现:Consul 通过 DNS 或者 HTTP 接口使服务注册

    2024年01月21日
    浏览(46)
  • Asp .Net Core 系列:基于 Swashbuckle.AspNetCore 包 集成 Swagger

    Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。它提供了一种规范的方式来定义、构建和文档化 RESTful Web 服务,使客户端能够发现和理解各种服务的功能。Swagger 的目标是使部署管理和使用功能强大的 API 从未如此简单。 Swagger 提供了

    2024年01月18日
    浏览(51)
  • Asp .Net Core 系列:集成 Ocelot+Consul实现网关、服务注册、服务发现

    Ocelot是一个开源的ASP.NET Core微服务网关,它提供了API网关所需的所有功能,如路由、认证、限流、监控等。 Ocelot是一个简单、灵活且功能强大的API网关,它可以与现有的服务集成,并帮助您保护、监控和扩展您的微服务。 以下是Ocelot的一些主要功能: 路由管理:Ocelot允许您

    2024年01月17日
    浏览(50)
  • 测试 ASP.NET Core 中间件

            正常情况下,中间件会在主程序入口统一进行实例化,这样如果想单独测试某一个中间件就很不方便,为了能测试单个中间件,可以使用 TestServer 单独测试。 这样便可以: 实例化只包含需要测试的组件的应用管道。 发送自定义请求以验证中间件行为。 这样测试

    2024年01月20日
    浏览(55)
  • C# 使用xUnit进行单元测试

    目录 写在前面 操作步骤  执行结果 xUnit.net 是 NUnit 的作者Jim Newkirk搞的一个新的单元测试框架,目的是解决 NUnit 存在的一些问题和缺点,并在框架中加入一些最佳实践和扩展能力。 主要的改进点如下: 为每个测试方法产生一个对象实例 取消了 [SetUp] 和 [TearDown] 取消了 [Ex

    2024年02月04日
    浏览(40)
  • Asp .Net Core 系列:集成 Ocelot+Nacos+Swagger+Cors实现网关、服务注册、服务发现

    什么是 Ocelot ? Ocelot是一个开源的ASP.NET Core微服务网关,它提供了API网关所需的所有功能,如路由、认证、限流、监控等。 Ocelot是一个简单、灵活且功能强大的API网关,它可以与现有的服务集成,并帮助您保护、监控和扩展您的微服务。 以下是Ocelot的一些主要功能: 路由管理

    2024年01月19日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包