本教程演示如何通过将测试项目添加到解决方案来自动执行单元测试。
先决条件
- 本教程适用于在使用 Visual Studio 创建 .NET 类库 源社区中创建的解决方案。
创建单元测试项目
单元测试在开发和发布期间提供自动化的软件测试。 MSTest 是可供选择的三个测试框架之一。 其他两个是 xUnit 和 nUnit。
启动 Visual Studio。
打开在ClassLibraryProjects中创建的 ClassLibraryProjects 解决方案。
将名为“StringLibraryTest”的新单元测试项目添加到解决方案。
- 在“解决方案资源管理器”中右键单击解决方案并选择“添加”“新建项目”。
- 在“添加新项目”页面,在搜索框中输入“mstest”。 从“语言”列表中选择“C#”或“Visual Basic”,然后从“平台”列表中选择“所有平台”。
- 选择“MSTest 测试项目”模板,然后选择“下一步” 。
- 在“配置新项目”页面,在“项目名称”框中输入“StringLibraryTest”。 然后选择“下一步” 。
- 在“其他信息”页的“框架”框中选择“.NET 6 (长期支持)” 。 然后选择“创建”。
此时,Visual Studio 会创建项目,并在具有以下代码的代码窗口中打开类文件。 如果未显示想要使用的语言,请更改页面顶部的语言选择器。
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace StringLibraryTest
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
}
}
}
单元测试模板创建的源代码负责执行以下操作:
- 它会导入 Microsoft.VisualStudio.TestTools.UnitTesting 命名空间,其中包含用于单元测试的类型。
- 向 UnitTest1 类应用 TestClassAttribute 特性。
- 它应用 TestMethodAttribute 特性来定义 C# 中的 TestMethod1 或 Visual Basic 中的 TestSub。
使用 [TestClass] 标记的测试类中标记有 [TestMethod] 的所有测试方法都会在单元测试运行时自动执行。
添加项目引用
对于要使用 StringLibrary 类的测试库,请在 StringLibraryTest 项目中添加对 StringLibrary 项目的引用。
- 在“解决方案资源管理器”中,右键单击“StringLibraryTest”项目的“依赖项”节点,并从上下文菜单中选择“添加项目引用” 。
- 在“引用管理器”对话框中,展开“项目”节点,并选择“StringLibrary”旁边的框 。 添加对 StringLibrary 程序集的引用后,编译器可以在编译 StringLibraryTest 项目时查找 StringLibrary 方法。
- 选择“确定”。
添加并运行单元测试方法
当 Visual Studio 运行单元测试时,它会执行使用 TestClassAttribute 特性标记的类中标记有 TestMethodAttribute 特性的所有方法。 当第一次遇到测试不通过或测试方法中的所有测试均已成功通过时,测试方法终止。
最常见的测试调用 Assert 类的成员。 许多断言方法至少包含两个参数,其中一个是预期的测试结果,另一个是实际的测试结果。 下表显示了 Assert 类最常调用的一些方法:
测试
StringLibrary.StartsWithUpper 方法时,需要提供许多以大写字符开头的字符串。 在这种情况下,此方法应返回 true,以便可以调用 Assert.IsTrue 方法。 同样,需要提供许多以非大写字符开头的字符串。 在这种情况下,此方法应返回 false,以便可以调用 Assert.IsFalse 方法。
由于库方法处理的是字符串,因此还需要确保它能够成功处理空字符串 ()(不含字符且 Length 为 0 的有效字符串)和 null 字符串(尚未初始化的字符串)。 可以直接将 StartsWithUpper 作为静态方法进行调用,并向其传递一个 String 自变量。 或者,可以对分配给 null 的 string 变量将 StartsWithUpper 作为扩展方法进行调用。
将定义三个方法,每个方法都会对字符串数组中的各个元素调用它的 Assert 方法。 你将调用方法重载,以便指定在测试失败时要显示的错误消息。 消息标识导致失败的字符串。
创建测试方法:
将 UnitTest1.cs 或 UnitTest1.vb 代码窗口中的代码替换为以下代码:
using Microsoft.VisualStudio.TestTools.UnitTesting;
using UtilityLibraries;
namespace StringLibraryTest
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestStartsWithUpper()
{
// Tests that we expect to return true.
string[] words = { "Alphabet", "Zebra", "ABC", "Αθήνα", "Москва" };
foreach (var word in words)
{
bool result = word.StartsWithUpper();
Assert.IsTrue(result,
string.Format("Expected for '{0}': true; Actual: {1}",
word, result));
}
}
[TestMethod]
public void TestDoesNotStartWithUpper()
{
// Tests that we expect to return false.
string[] words = { "alphabet", "zebra", "abc", "αυτοκινητοβιομηχανία", "государство",
"1234", ".", ";", " " };
foreach (var word in words)
{
bool result = word.StartsWithUpper();
Assert.IsFalse(result,
string.Format("Expected for '{0}': false; Actual: {1}",
word, result));
}
}
[TestMethod]
public void DirectCallWithNullOrEmpty()
{
// Tests that we expect to return false.
string?[] words = { string.Empty, null };
foreach (var word in words)
{
bool result = StringLibrary.StartsWithUpper(word ?? string.Empty);
Assert.IsFalse(result,
string.Format("Expected for '{0}': false; Actual: {1}",
word == null ? "<null>" : word, result));
}
}
}
}
TestStartsWithUpper 方法中的大写字符的测试包括希腊文大写字母 alpha (U+0391) 和西里尔文大写字母 EM (U+041C)。 TestDoesNotStartWithUpper 方法中的小写字符的测试包括希腊文小写字母 alpha (U+03B1) 和西里尔文小写字母 Ghe (U+0433)。
在菜单栏上,选择“文件”“将 UnitTest1.cs 另存为”或“文件”“将 UnitTest1.vb 另存为”。 在“文件另存为”对话框中,选择“保存”按钮旁边的箭头,然后选择“保存时使用编码”。
![20220517224055307 20220517224055307](https://cfiles.51aspx.com/wp-content/uploads/2022/04/20220517224055307.jpg)
在“确认另存为”对话框中,选择“是”按钮,保存文件。
在“高级保存选项”对话框的“编码”下拉列表中,选择“Unicode (UTF-8 带签名) - 代码页 65001”,然后选择“确定”。
![20220517224055249 20220517224055249](https://cfiles.51aspx.com/wp-content/uploads/2022/04/20220517224055249.jpg)
如果无法将源代码保存为 UTF8 编码文件,Visual Studio 可能会将其另存为 ASCII 文件。 在这种情况下,运行时将无法准确解码 ASCII 范围以外的 UTF8 字符,且测试结果也会不正确。
在菜单栏上,选择“测试”“运行所有测试”。 如果“测试资源管理器”窗口未打开,请选择“测试”“测试资源管理器”来将其打开。 “通过的测试”部分列出了三个测试,“摘要”部分报告了测试运行结果。
![20220517224056384 20220517224056384](https://cfiles.51aspx.com/wp-content/uploads/2022/04/20220517224056384.jpg)
处理测试失败
如果进行的是测试驱动开发 (TDD),请先编写测试,然后测试会在第一次运行时失败。 接着将可以使测试成功的代码添加到应用。 在本教程中,先编写了测试要验证的应用代码然后才创建测试,所以没有看到测试失败。 若要验证测试是否在预期失败时失败,请在测试输入中添加无效值。
通过修改 TestDoesNotStartWithUpper 方法中的 words 数组来包含字符串“Error”。 由于 Visual Studio 将在生成运行测试的解决方案时自动保存打开的文件,因此无需手动保存。
string[] words = { "alphabet", "Error", "zebra", "abc", "αυτοκινητοβιομηχανία", "государство",
"1234", ".", ";", " " };
从菜单栏中选择“测试”“运行所有测试”,运行测试。 “测试资源管理器”窗口指示有两个测试成功,还有一个失败。
![20220517224058187 20220517224058187](https://cfiles.51aspx.com/wp-content/uploads/2022/04/20220517224058187.jpg)
选择失败的测试,TestDoesNotStartWith。
“测试资源管理器”窗口显示断言生成的消息:“Assert.IsFalse 失败。 “Error”应返回 false;实际返回 True”。 由于此次失败,数组中“Error”之后的所有字符串都未进行测试。
![20220517224059562 20220517224059562](https://cfiles.51aspx.com/wp-content/uploads/2022/04/20220517224059562.jpg)
删除在步骤 1 中添加的字符串“Error”。 重新运行测试,测试将通过。
测试库的发行版本
至此,在运行库的调试版本时,测试已全部通过,接下来应对库的发行版本再运行一次这些测试。 许多因素(包括编译器优化)有时可能会导致调试版本和发行版本出现行为差异。
若要测试发行版本,请执行以下操作:
在 Visual Studio 工具栏中,将生成配置从 “调试” 更改为 “发行” 。
![20220517224059202 20220517224059202](https://cfiles.51aspx.com/wp-content/uploads/2022/04/20220517224059202.jpg)
在“解决方案资源管理器”中,右键单击“StringLibrary”项目,从上下文菜单中选择“生成”,重新编译库。
![20220517224100193 20220517224100193](https://cfiles.51aspx.com/wp-content/uploads/2022/04/20220517224100193.jpg)
从菜单栏中选择“测试运行”“所有测试”,运行单元测试。 测试通过。
调试测试
如果使用 Visual Studio 作为 IDE,则可以使用教程:使用 Visual Studio 调试 .NET 控制台应用程序 – 源社区中所示的相同过程,使用单元测试项目来调试代码。 右键单击“StringLibraryTests”项目,然后从上下文菜单中选择“调试测试”,而不是启动 ShowCase 应用项目。
Visual Studio 启动附有调试器的测试项目。 执行将在添加到测试项目的任何断点或基础库代码处停止。
4月19日 周二 19:30 今晚.NET云原生挑战赛直播课-第四课【桂素伟-开发基于Docker的.NET 应用】 关注 51Aspx视频号观看,往期录播视频
https://club.51aspx.com/bigcowteaching/
![20220517224101595 20220517224101595](https://cfiles.51aspx.com/wp-content/uploads/2022/04/20220517224101595.jpg)