mcpField
C
csharp-tunit

csharp-tunit

github.com/midudev测试与质量7.0k58 次安装1 周前更新
代码仓库

关于 csharp-tunit

TUnit Best Practices 是用于在 .NET 项目中编写 TUnit 单元测试的技能,介绍测试结构、异步流畅断言、数据驱动测试、生命周期钩子、并行执行及从 xUnit 迁移。

主要功能

  1. 01测试结构与 AAA 模式
  2. 02内联、方法和类级测试数据
  3. 03异步流畅断言
  4. 04生命周期钩子与测试组织
  5. 05并行执行与测试控制
  6. 06xUnit 迁移指引

适用场景

  1. 01为 .NET 8 及以上版本创建 TUnit 测试项目
  2. 02编写数据驱动的单元测试
  3. 03将测试从 xUnit 迁移至 TUnit

安装

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

$npx skills add https://github.com/midudev/autoskills --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