演练:创建并运行单元测试
本演练将逐步指导您使用 Microsoft Visual Studio 2010 来创建、运行和自定义一系列测试。 您将从正处于开发过程中的 C# 项目开始,创建执行该项目代码的测试,运行测试并检查结果。 然后,可以更改项目代码并重新运行测试。
提示
有关如何从命令行运行测试的信息,请参见演练:使用命令行测试实用工具。
在本演练中,您将完成以下任务:
准备一个要在演练中使用的“银行帐户”项目。
打开一个现有项目。
为公共和私有方法创建单元测试。
对代码运行这些测试。
在测试中查找错误并进行更正。
在代码中查找错误并进行更正。
系统必备
- Woodgrove Bank 项目。 请参见用于创建单元测试的示例项目。
准备演练
准备演练
打开 Visual Studio 2010 高级专业版。
在**“文件”菜单上指向“新建”,然后单击“项目”**。
此时将出现**“新建项目”**对话框。
在**“已安装的模板”下单击“Visual C#”**。
在应用程序类型的列表中单击**“类库”**。
在**“名称”框中键入 Bank,然后单击“确定”**。
提示
如果名称“Bank”已被使用,请为该项目选择其他名称。
将创建新的 Bank 项目并将其显示在解决方案资源管理器中,而且将在代码编辑器中打开 Class1.cs 文件。
提示
如果代码编辑器中未打开 Class1.cs 文件,请在解决方案资源管理器中双击文件 Class1.cs 将其打开。
从用于创建单元测试的示例项目中复制源代码。
用用于创建单元测试的示例项目中的代码替换 Class1.cs 的原始内容。
在**“生成”菜单上,单击“生成解决方案”**。
现在您有一个名为“Bank”的项目。 它包含要测试的源代码和用于对该源代码进行测试的工具。 Bank 的命名空间**“BankAccountNS”包含公共类“BankAccount”**,在以下过程中将对该类的方法进行测试。
创建单元测试
系统必备:按照准备演练过程中的步骤执行操作。
创建单元测试
如果代码编辑器中未打开 Class1.cs 文件,请在解决方案资源管理器中双击 Bank 项目中的 Class1.cs 文件。
在 Class1.cs 文件的**“BankAccount”类中,滚动到“Debit()”**方法。
右击**“Debit()”方法,然后选择“创建单元测试”**。
将显示**“创建单元测试”**对话框。
在**“当前选择”下,树结构将显示保存“BankAccount”**类的程序集的类和成员层次结构。 使用此页可以为选定的任何成员生成单元测试,并可以选择要在其中放置生成的单元测试的测试项目。
在该树结构中,只选择了**“Debit()”方法。 将其保留选定状态并选择“Credit()”**方法。
对于**“输出项目”,请选择“创建新的 Visual C# 测试项目”**。
单击**“设置”**。
随即出现**“测试生成设置”对话框。 在“命名设置”下,可以更改测试文件、测试类和测试方法在生成时的命名方式。 在“常规”下,可以更改测试生成的其他方面。 将这些设置保留为默认值,然后单击“确定”**。
在**“创建单元测试”对话框中单击“确定”**。
随即出现**“新建测试项目”**对话框。
接受默认名称,然后单击**“创建”**。
这将创建一个名为 TestProject1 的项目,该项目将显示在解决方案资源管理器中。
一个名为 BankAccountTest.cs 的文件添加到 TestProject1 中,该文件包含一个测试类。 该类中填充有一个 TestContext 属性以及测试**“Debit()”和“Credit()”**方法的方法。
提示
将自动为每个测试方法分配“TestMethod()”特性。 每个测试都与要测试的测试代码中的一个方法相对应。 测试方法保存在已分配“TestClass()”特性的测试类中。
在 BankAccountTest.cs 中,指定要测试的变量的值。 滚动到**“DebitTest”**方法,在此可以看到 // TODO 行,它们指示要设置的变量。
若要了解 DebitTest 方法将使用哪些值,请打开 Class1.cs 文件并滚动到**“Main”方法。 请注意,客户名称初始化为“Mr. Bryan Walton”,帐户余额初始化为“11.99”,调用“Credit”方法时使用参数“5.77”,调用“Debit”方法时使用参数“11.22”。 因此,如果此帐户开始时“Balance”为“11.99”,则在传递“11.22”时调用“Debit”方法应生成新“Balance”值“0.77”**。
提示
在本演练后面的部分中,您将使用此预期的“Balance”值 (0.77)。
在 BankAccountTest.cs 文件中,滚动到**“DebitTest”**方法。
设置下列值:
BankAccount target = new BankAccount("Mr. Bryan Walton", 11.99); double amount = 11.22;
在**“CreditTest”**方法中,将“Mr. Bryan Walton”和 11.99 添加到新的 BankAccount 中。
保存 BankAccountTest.cs 文件。
您已创建了一个源代码文件,其中包含 Bank 项目的测试。 现在可以对 Bank 项目的代码运行**“BankAccountTest”**类中的测试了。
运行和自定义单元测试
系统必备:执行创建单元测试过程中的步骤。
运行和自定义单元测试
在**“测试”菜单上,单击“窗口”,然后选择“测试视图”**。
将显示“测试视图”窗口。
右击**“DebitTest”,再单击“运行选定内容”**。
如果**“测试结果”**窗口尚未打开,则它现在将打开。 **“DebitTest”**测试运行。
在**“测试结果”窗口的“结果”列中,当测试运行时,测试状态将显示为“正在运行”。 测试运行完成后,测试的结果将更改为“没有结论”**。
在**“测试结果”窗口中右击表示测试的行,然后单击“查看测试结果详细信息”**。
在**“测试结果详细信息”页中,将显示错误消息“Assert.Inconclusive 失败。 无法验证不返回值的方法。”若要创建成功的测试,请先查找并评估此“Assert”**语句。
若要查找包含**“Assert”语句的测试方法,请打开 BankAccountTest.cs 文件并滚动到“DebitTest()”**方法。
Assert 语句是**“DebitTest”**方法中的最后一行。 它显示如下内容:
Assert.Inconclusive("A method that does not return a value cannot be verified.");
注释掉此 Assert 语句。
如果现在运行测试,则会得出**“已通过”结果,但这仅仅是因为它没有对任何内容进行测试。 必须添加对预期的结果进行测试的代码。 向“DebitTest”**方法的末尾添加以下语句:
Assert.AreEqual((System.Convert.ToDouble(0.77)), target.Balance, 0.05);
此语句将预期结果 (0.77) 与调用**“BankAccount”类的“Balance”方法所产生的实际结果进行比较。 如果两个值不相等,则“Assert”返回“False”**,从而使测试失败。
提示
此“Assert”语句还包括第三个参数“delta”,其值为 0.05。 在“Assert.AreEqual”方法的此重载中需要该 delta 参数;它可以补偿“Doubles”等浮点型所固有的舍入错误。
您已运行了**“BankAccountTest”测试类的生成的“DebitTest”方法,注意它需要做的更改,请就此做出这些更改。 现在,可以测试您应用程序中“Debit”**方法的精确性。
运行单元测试并修复代码
系统必备:执行运行和自定义单元测试过程中的步骤。
运行单元测试并修复代码
再次运行 Debit 测试:在文件 BankAccountTest.cs 中,右击**“DebitTest()”方法,然后单击“运行测试”**。
在“测试结果”窗口的**“结果”列中,当测试运行时,测试状态将显示为“正在运行”。 测试运行完成后,测试的结果将更改为“未通过”**。
在“测试结果”窗口中右击表示测试的行,然后单击**“查看测试结果详细信息”**。
这将打开“测试结果详细信息”页,其中显示以下错误消息:“Assert.AreEqual 失败。 预期值 <0.77> 和实际值 <23.21> 之间的差不应大于 <0.05>”。 这些数字似乎表明数学运算不正确。 由于**“BankAccountTest”类的“DebitTest”方法测试“BankAccount”类的“Debit”方法,所以从检查“Debit”**方法开始。
打开 Class1.cs 文件并滚动到**“Debit”**方法。
请注意以下赋值:
m_balance += amount;
此赋值向余额增加金额,在**“Debit”**方法中,应当减去赋值。 将此行更改为:
m_balance -= amount;
再次运行**“Debit”**测试。
在“测试结果”窗口的**“结果”列中,将为“DebitTest”显示“已通过”**。
提示
更改源代码后不必重新生成测试项目,因为运行测试时会生成项目而不进行提示。
您创建了一个可以运行的单元测试,并通过它查找和修复了代码中的错误。
为私有方法创建和运行单元测试
系统必备:执行运行单元测试并修复代码过程中的步骤。
为私有方法创建和运行单元测试
打开 Bank 项目中的 Class1.cs 文件。
右击**“FreezeAccount()”方法,然后选择“创建单元测试”**。
随即出现**“创建单元测试”**对话框。
在显示的树结构中,只有**“FreezeAccount()”**方法处于选定状态。
(可选)单击**“筛选器”,然后清除“显示非公共项”。 注意,“FreezeAccount()”方法已从 BankAccount 类的子方法列表中移除。 再次单击“筛选器”,然后选择“显示非公共项”以重新显示“FreezeAccount()”**方法。
确保**“FreezeAccount()”方法处于选中状态,然后单击“确定”**。
此时将新建一个名为 Bank.accessor 的专用访问器文件。 该文件中包含特殊的访问器方法,测试使用这些方法间接调用 BankAccount 类中的私有方法。 在解决方案资源管理器的“测试引用”文件夹中可以看到这个新文件。
打开 BankAccountTest.cs 文件并滚动到**“FreezeAccountTest()”**方法。
更改**“FreezeAccountTest()”**方法的代码,使其与下面所示的代码一致。 更改过的区域或新区域有相应的指示:
public void FreezeAccountTest() { BankAccount_Accessor target = new BankAccount_Accessor("Mr. Bryan Walton", 11.99); // TODO: Initialize to an appropriate value target.FreezeAccount(); // Assert.Inconclusive("A method that does not return a value cannot be verified."); bool creditAccount = false; // False means account could be credited: Fail test. // Try to credit account try { target.Credit(1.00); } catch (System.Exception) { // Threw exception. FreezeAccount worked correctly: Pass test. creditAccount = true; } // Assert fails if 'creditAccount' condition is false. Fail test. Assert.IsTrue(creditAccount, "Was able to credit account."); }
运行**“FreezeAccountTest”**测试。
在“测试结果”窗口的**“结果”列中,最终测试状态显示为“已通过”。 该结果与预期结果一致,原因是测试在调用“FreezeAccount()”方法冻结帐户之后调用了“Credit()”**方法。
您已经添加了一个私有方法,为其创建了新的单元测试并运行了该测试。 可以对 balance 变量使用其他边界值(如 15.00)来多次运行该测试。
后续步骤
对程序集中的代码运行测试时,可以通过收集代码覆盖率数据来查看正在测试的项目代码部分。 有关更多信息,请参见演练:运行测试并查看代码覆盖率。
可以在命令行中(而不是在 Visual Studio 中)运行测试。 有关更多信息,请参见演练:使用命令行测试实用工具。
如果正在使用 Visual Studio 2010 旗舰版,则可以使用单元测试创建负载测试以隔离压力和性能问题。