使用 XUnit 的测试驱动开发过程

介绍
什么是测试驱动开发
测试驱动开发或(简称 TDD)是强调重构代码和创建单元测试作为主要软件开发周期的一部分的软件开发过程。

在最纯粹的形式中,TDD 鼓励首先创建测试,然后为测试的功能创建实现。

然而,我相信软件开发应该由功能需求驱动,而不是测试,因此在本文中,我演示了一种改进的(适度的)TDD 方法,它强调重构和单元测试创​​建作为主编码周期。

这是一张详细说明 TDD 开发周期的图表:

图片 1

如果您有点困惑,请不要担心 - 我们将在描述示例时详细介绍这个开发周期。

请注意,上面介绍的 TDD 周期的前 3 个步骤(包括重构)可以而且应该连续用于任何开发,即使跳过了测试:

图 2

这个循环可以称为重构编码。 

这个周期也将成为未来文章中描述的原型驱动开发的一部分。

TDD优势
鼓励开发人员将可重用功能分解为可重用方法和类。
单元测试与功能一起创建(不仅是在开发人员有空闲时间时)。
TDD 缺点
有时甚至为琐碎的代码创建了太多测试,导致在测试创建上花费了太多时间,并且在运行这些测试上花费了太多计算机资源,从而导致构建速度变慢。

构建的缓慢也可能会进一步显着减慢开发速度。

由于超级缓慢的构建,我看到整个项目几乎停滞不前。 

正因为如此,哪些功能需要测试,哪些不需要,应该运行哪些测试以及多久运行一次,应该由经验丰富的项目架构师来决定,并在项目开发过程中根据需要进行调整。

不同的项目可能需要不同的 TDD 指南,这取决于它们的规模、重要性、资金、截止日期、开发人员的数量和经验以及 QA 资源。

示例代码
生成的示例代码位于TDD Cycle Sample Code下。

请注意,由于本文的目的是介绍该过程,因此您必须从空项目开始阅读本教程,并完成最终生成示例代码的每个步骤。

我在示例中使用了 Visual Studio 2022 和 .NET 6,但稍作修改(主要与Program.Main(...)方法相关)后,也可以使用旧版本的 .NET 和 Visual Studio。

我使用流行的(也许是最流行的)XUnit框架来创建和运行单元测试。

测试驱动开发视频
TDD Development Cycle Video上还有一个 TDD 视频,内容相同。

为获得最佳效果,我建议阅读本文、浏览演示并观看视频。

TDD 开发周期演示
从几乎为空的解决方案开始
您的初始解决方案应仅包含三个项目:

主要项目MainApp
可重用项目NP.Utilities(在Core文件夹下)
单元测试项目NP.Utilities.Test(在测试文件夹下)
图 3

MainApp的Program.cs文件应该是完全空的(记住它是 .NET 6)。

项目的文件StringUtils.csNP.Utilities可以包含一个空的public static class:

C#
public static class StringUtils { }
主项目和测试项目都应该引用NP.Utilities可重用项目。

测试项目NP.Utility.Test还应引用 XUnit 和其他两个 NuGet 包:

图 4

为了能够在 Visual Studio 中调试 XUnit 测试,需要两个额外的 nuget 包“ Microsoft.NET.Test.SDK”和“ ”。xunit.runner.visualstudio

获取初始(几乎为空)解决方案的最简单方法是下载或 git-cloning TDD Cycle Sample Code,运行src/MainApp/MainApp.sln解决方案,从MainApp/Program.cs和NP.Utilities中删除所有代码/StringUtils.cs文件并删除文件NP.Utility.Tests/Test_StringUtils.cs。

您也可以尝试自己创建这样的解决方案(不要忘记提供项目和 nuget 包依赖项)。

新功能的要求
假设您正在主解决方案的Program.cs文件中创建新功能。

还假设,您需要创建新功能以将字符串 " Hello World!" 拆分为两个strings - 一个在 " " 字符的第一个实例之前,ll一个在相同字符之后 - 当然,这两个结果字符串将是 " He" 和 " o World!" .

首先在Program.cs文件中定义初始字符串和分隔符字符串:

C#
string str = "Hello World!";
string separator = "ll"; // startStrPart="He" endStrPart="o World!"  
另请注意 - 我们在行注释中提到了开始和结束结果部分。

重要说明:出于本演示的目的,我们假设该方法string.Split(...)不存在,即使我们使用string类型 (string.Substring(...)和中的一些更简单的方法string.IndexOf(...))。本质上,我们重新实现了一个特殊的更简单版本Split(...),它只围绕第一个实例进行拆分分隔符并将结果作为元组而不是数组返回。

内联创建新功能 - 最接近它的使用位置
我们首先在同一个Program.cs文件中以最简单、直接、不可重用的方式在使用它的地方创建新功能:

你可能感兴趣的:(驱动开发)