在 C# 中,单元测试聚焦于隔离验证单个方法或类的逻辑,不依赖数据库、网络等外部资源;集成测试则验证多个组件(如 API、数据库、中间件)协同工作是否正常。两者通常分属不同的测试项目,使用 MSTest、xUnit 或 NUnit 框架编写,并通过dotnet test或 Visual Studio 测试资源管理器运行。
单元测试怎么写
核心原则:每个测试只验证一个行为,遵循 Arrange(准备)—Act(执行)—Assert(断言)的 3A 模式,避免依赖外部资源。
创建测试项目:在解决方案中新增一个测试项目(如 MSTest 或 xUnit 模板),并添加对被测项目的引用。若使用 CLI,可执行dotnet new xunit -o MyProject.Tests,再通过dotnet add reference添加项目引用。
编写测试方法:以 MSTest 为例,测试类标记[TestClass],测试方法标记[TestMethod],方法必须为public void且无参数。xUnit 则用[Fact]标记独立测试,[Theory]配合[InlineData]做参数化测试。
示例:假设有一个BankAccount类,测试其Debit方法在合法金额下是否正确扣款。
[TestClass]publicclassBankAccountTests{[TestMethod]publicvoidDebit_WithValidAmount_UpdatesBalance(){// ArrangedoublebeginningBalance=11.99;doubledebitAmount=4.55;doubleexpected=7.44;varaccount=newBankAccount("Mr. Walton",beginningBalance);// Actaccount.Debit(debitAmount);// AssertAssert.AreEqual(expected,account.Balance,0.001,"扣款金额不正确");}}上述代码来自 Microsoft 官方演练,测试失败时会明确提示预期值与实际值的差异。对于异常测试,可用Assert.ThrowsException<ArgumentOutOfRangeException>(() => account.Debit(-100))验证是否抛出预期异常。
运行测试:Visual Studio 中打开“测试资源管理器”点击“全部运行”;CLI 中在解决方案目录执行dotnet test。
集成测试怎么写(以 ASP.NET Core API 为例)
核心工具:使用Microsoft.AspNetCore.Mvc.Testing包中的WebApplicationFactory<TProgram>,它能在内存中启动完整的应用管道,让你用HttpClient发送真实 HTTP 请求,而无需部署到服务器。
基本步骤:在测试项目中引用 Web 项目,并添加Microsoft.AspNetCore.Mvc.TestingNuGet 包。在 Web 项目的Program.cs末尾添加public partial class Program { },以便测试项目能访问到入口点。
自定义工厂:若需替换数据库(如用内存数据库代替真实 SQL Server),继承WebApplicationFactory<Program>并重写ConfigureWebHost,在ConfigureServices中移除原有的数据库注册,替换为测试用的数据库上下文。
示例测试:以下测试验证 GET 请求/返回成功状态码。
publicclassIndexPageTests:IClassFixture<CustomWebApplicationFactory<Program>>{privatereadonlyHttpClient_client;publicIndexPageTests(CustomWebApplicationFactory<Program>factory){_client=factory.CreateClient();}[Fact]publicasyncTaskGet_Root_ReturnsSuccess(){// Actvarresponse=await_client.GetAsync("/");// Assertresponse.EnsureSuccessStatusCode();// 若状态码非 2xx 则失败}}对于需要验证具体内容的测试(如检查页面中的某个元素),可以获取响应字符串后用 HTML 解析库(如 AngleSharp)处理。若需模拟已登录用户,可通过自定义AuthenticationHandler注入测试身份,或直接在请求头中携带测试令牌。
关键区别与选择建议
| 维度 | 单元测试 | 集成测试 |
|---|---|---|
| 范围 | 单个类/方法 | 多个组件协作(API + DB + 中间件) |
| 速度 | 毫秒级,极快 | 相对较慢(需启动管道、初始化 DB) |
| 依赖 | 无外部依赖(用 Mock 隔离) | 有依赖(但可用内存数据库/Testcontainers 替代) |
| 失败定位 | 直接指向具体方法逻辑 | 需排查是哪个环节出问题 |
实践建议:大量编写单元测试覆盖核心业务逻辑与边界条件,少量集成测试覆盖关键 API 端点和数据访问路径。单元测试中若被测类依赖外部服务,使用 Moq 等框架模拟接口,确保测试纯粹且快速。集成测试中若需接近生产环境的数据库行为,可考虑用 Testcontainers 启动真实数据库容器,但会牺牲一些速度。