mcpField
C
csharp-tunit

csharp-tunit

github.com/github测试与质量40.5k8.8k 次安装1 天前更新
代码仓库

关于 csharp-tunit

csharp-tunit 是面向 .NET 项目的 TUnit 单元测试编写技能,涵盖测试结构、断言、数据驱动用例、生命周期钩子及从 xUnit 迁移的指导。

主要功能

  1. 01AAA 测试结构
  2. 02流畅的异步断言
  3. 03数据驱动测试模式
  4. 04生命周期与执行控制
  5. 05xUnit 迁移指导

适用场景

  1. 01编写专注的 TUnit 单元测试
  2. 02添加内联或方法式测试数据
  3. 03管理设置与清理钩子
  4. 04将 xUnit 测试迁移到 TUnit

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/github/awesome-copilot --skill csharp-tunit

安装后在 Claude Code 中输入/csharp-tunit确认已加载。

详细介绍

TUnit 最佳实践

你的目标是帮助我使用 TUnit 编写有效的单元测试,涵盖标准测试和数据驱动测试两种方式。

项目设置

  • 使用单独的测试项目,命名约定为 [ProjectName].Tests
  • 引用 TUnit 包和 TUnit.Assertions 以实现流式断言
  • 创建与被测类匹配的测试类(例如,为 Calculator 创建 CalculatorTests)
  • 使用 .NET SDK 测试命令:dotnet test 运行测试
  • TUnit 需要 .NET 8.0 或更高版本

测试结构

  • 无需测试类特性(如 xUnit/NUnit)
  • 对测试方法使用 [Test] 特性(不是 xUnit 的 [Fact])
  • 遵循 Arrange-Act-Assert(AAA)模式
  • 使用 MethodName_Scenario_ExpectedBehavior 模式命名测试
  • 使用生命周期钩子:[Before(Test)] 用于设置,[After(Test)] 用于清理
  • 使用 [Before(Class)] 和 [After(Class)] 在同一类的测试之间共享上下文
  • 使用 [Before(Assembly)] 和 [After(Assembly)] 在测试类之间共享上下文
  • TUnit 支持高级生命周期钩子,如 [Before(TestSession)] 和 [After(TestSession)]

标准测试

  • 让测试专注于单一行为
  • 避免在一个测试方法中测试多个行为
  • 使用 TUnit 的流式断言语法 await Assert.That()
  • 仅包含验证测试用例所需的断言
  • 使测试独立且幂等(可以按任意顺序运行)
  • 避免测试相互依赖(如需要,使用 [DependsOn] 特性)

数据驱动测试

  • 使用 [Arguments] 特性提供内联测试数据(等同于 xUnit 的 [InlineData])
  • 使用 [MethodData] 提供基于方法的测试数据(等同于 xUnit 的 [MemberData])
  • 使用 [ClassData] 提供基于类的测试数据
  • 通过实现 ITestDataSource 创建自定义数据源
  • 在数据驱动测试中使用有意义的参数名称
  • 可以将多个 [Arguments] 特性应用于同一个测试方法

断言

  • 使用 await Assert.That(value).IsEqualTo(expected) 进行值相等断言
  • 使用 await Assert.That(value).IsSameReferenceAs(expected) 进行引用相等断言
  • 使用 await Assert.That(value).IsTrue() 或 await Assert.That(value).IsFalse() 进行布尔条件断言
  • 使用 await Assert.That(collection).Contains(item) 或 await Assert.That(collection).DoesNotContain(item) 进行集合断言
  • 使用 await Assert.That(value).Matches(pattern) 进行正则表达式模式匹配
  • 使用 await Assert.That(action).Throws<TException>() 或 await Assert.That(asyncAction).ThrowsAsync<TException>() 测试异常
  • 使用 .And 运算符链接断言:await Assert.That(value).IsNotNull().And.IsEqualTo(expected)
  • 使用 .Or 运算符表示备选条件:await Assert.That(value).IsEqualTo(1).Or.IsEqualTo(2)
  • 使用 .Within(tolerance) 进行带容差的 DateTime 和数值比较
  • 所有断言都是异步的,必须使用 await

高级功能

  • 使用 [Repeat(n)] 将测试重复多次
  • 使用 [Retry(n)] 在失败时自动重试
  • 使用 [ParallelLimit<T>] 控制并行执行限制
  • 使用 [Skip("reason")] 有条件地跳过测试
  • 使用 [DependsOn(nameof(OtherTest))] 创建测试依赖关系
  • 使用 [Timeout(milliseconds)] 设置测试超时
  • 通过扩展 TUnit 的基类特性创建自定义特性

测试组织

  • 按功能或组件对测试分组
  • 使用 [Category("CategoryName")] 进行测试分类
  • 使用 [DisplayName("Custom Test Name")] 自定义测试名称
  • 考虑使用 TestContext 进行测试诊断和信息获取
  • 使用条件特性,如自定义 [WindowsOnly],用于特定平台的测试

性能与并行执行

  • TUnit 默认并行运行测试(不同于需要显式配置的 xUnit)
  • 使用 [NotInParallel] 为特定测试禁用并行执行
  • 使用 [ParallelLimit<T>] 搭配自定义限制类来控制并发
  • 同一类中的测试默认按顺序运行
  • 使用 [Repeat(n)] 搭配 [ParallelLimit<T>] 应对负载测试场景

从 xUnit 迁移

  • 将 [Fact] 替换为 [Test]
  • 将 [Theory] 替换为 [Test],并使用 [Arguments] 提供数据
  • 将 [InlineData] 替换为 [Arguments]
  • 将 [MemberData] 替换为 [MethodData]
  • 将 Assert.Equal 替换为 await Assert.That(actual).IsEqualTo(expected)
  • 将 Assert.True 替换为 await Assert.That(condition).IsTrue()
  • 将 Assert.Throws<T> 替换为 await Assert.That(action).Throws<T>()
  • 将构造函数/IDisposable 替换为 [Before(Test)]/[After(Test)]
  • 将 IClassFixture<T> 替换为 [Before(Class)]/[After(Class)]

为什么选择 TUnit 而非 xUnit?

TUnit 提供现代、快速且灵活的测试体验,具备 xUnit 所没有的高级功能,例如异步断言、更精细的生命周期钩子以及更强大的数据驱动测试能力。TUnit 的流畅断言提供更清晰、更具表达力的测试验证,尤其适合复杂的 .NET 项目。

评论

支持 Markdown