C# 测试:Unit、Integration、E2E 从入门到精通

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

引言:为什么需要在 C# 中进行测试?

\n

在现代 C# (.NET) 开发中,代码质量不是奢侈品,而是必需品。测试不仅可以在代码进入生产环境之前捕获错误,还可以作为活文档,并加速重构过程。有三个主要的测试层级构成了“测试金字塔”:Unit(单元测试)、Integration(集成测试)和 E2E(端到端测试)。在本文中,我们将通过真实的 C# 代码示例来逐一解析它们。

\n\n

1. 单元测试:质量的基础

\n

单元测试在脱离外部依赖(数据库、文件系统、API)的情况下,检查代码的独立片段(方法、类)。在 .NET 生态系统中,有三个流行的框架:xUnit(推荐用于新项目)、NUnit 和 MSTest。

\n\n

基本原则 (FIRST)

\n
    \n
  • Fast — 快速(毫秒级)。
  • \n
  • Isolated — 隔离(使用 mock)。
  • \n
  • Repeatable — 可重复。
  • \n
  • Self-validating — 自我验证(Assert)。
  • \n
  • Timely — 及时。
  • \n
\n\n

使用 xUnit 和 Moq 的单元测试示例

\n

假设我们有一个用于计算折扣的服务:

\n
public interface IDiscountService\n{\n    decimal CalculateDiscount(decimal price, bool isLoyaltyMember);\n}\n\npublic class DiscountService : IDiscountService\n{\n    public decimal CalculateDiscount(decimal price, bool isLoyaltyMember)\n    {\n        if (isLoyaltyMember) return price * 0.9m; // 10% 折扣\n        return price;\n    }\n}
\n

使用 Moq(用于模拟依赖)和 xUnit 的测试:

\n
using Xunit;\nusing Moq;\n\npublic class DiscountServiceTests\n{\n    [Fact]\n    public void CalculateDiscount_WhenLoyaltyMember_ReturnsDiscountedPrice()\n    {\n        // Arrange\n        var service = new DiscountService();\n        var price = 100m;\n\n        // Act\n        var result = service.CalculateDiscount(price, true);\n\n        // Assert\n        Assert.Equal(90m, result);\n    }\n\n    [Theory]\n    [InlineData(100, false, 100)]\n    [InlineData(200, true, 180)]\n    public void CalculateDiscount_MultipleCases_ReturnsCorrectValues(decimal price, bool isLoyalty, decimal expected)\n    {\n        var service = new DiscountService();\n        var result = service.CalculateDiscount(price, isLoyalty);\n        Assert.Equal(expected, result);\n    }\n}
\n

建议: 使用 [Fact] 属性进行单个测试,使用 [Theory] + [InlineData] 进行参数化测试。

\n\n

2. 集成测试:检查组件之间的协作

\n

集成测试检查多个模块如何协同工作——例如,控制器、服务和真实数据库(或其替代品,如内存中的 SQLite)。在 ASP.NET Core 中,使用 WebApplicationFactory 来实现这一点。

\n\n

配置 WebApplicationFactory

\n

创建一个测试类,用于启动测试 Web 主机:

\n
using Microsoft.AspNetCore.Mvc.Testing;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.Extensions.DependencyInjection;\nusing MyApp.Data;\n\npublic class CustomWebApplicationFactory : WebApplicationFactory<Program>\n{\n    protected override void ConfigureWebHost(IWebHostBuilder builder)\n    {\n        builder.ConfigureServices(services =>\n        {\n            // 移除真实的 DbContext\n            var descriptor = services.SingleOrDefault(\n                d => d.ServiceType == typeof(DbContextOptions<AppDbContext>));\n            if (descriptor != null) services.Remove(descriptor);\n\n            // 添加内存数据库\n            services.AddDbContext<AppDbContext>(options =>\n                

博客

书籍推荐