演练:创建并运行单元测试

更新:2007 年 11 月

此演练将逐步指导您使用 Team System 测试工具 来创建、运行和自定义一系列测试。您将从正处于开发过程中的 C# 项目开始,创建执行该项目代码的测试,运行测试并检查结果。然后,可以更改项目代码并重新运行测试。

说明:

有关如何从命令行运行测试的信息,请参见演练:使用命令行测试实用工具

在本演练中,您将完成以下任务:

  • 准备一个要在演练中使用的“银行帐户”项目。

  • 打开一个现有项目。

  • 为公共和私有方法创建单元测试。

  • 对代码运行这些测试。

  • 在测试中查找错误并进行更正。

  • 在代码中查找错误并进行更正。

先决条件

准备演练

准备演练

  1. 打开 Visual Studio Team System Test Edition。

  2. 在“文件”菜单上指向“新建”,然后单击“项目”。

    随即出现“新建项目”对话框。

  3. 在“项目类型”之下单击“Visual C#”。

  4. 在“模板”之下单击“类库”。

  5. 在“名称”行中,键入 Bank,然后单击“确定”。

    说明:

    如果名称“Bank”已被使用,请为该项目选择其他名称。

    新的 Bank 项目即被创建,并显示在解决方案资源管理器中。

  6. 在解决方案资源管理器中双击 Class1.cs 文件,以便在 Visual Studio 代码编辑器中打开它。

  7. 单元测试示例中复制源代码。

  8. 单元测试示例中的代码替换 Class1.cs 的原始内容。

  9. 在“生成”菜单上,单击“生成解决方案”。

现在您有一个名为“Bank”的项目。它包含要测试的源代码和用于对该源代码进行测试的工具。Bank 的命名空间“BankAccountNS”包含公共类“BankAccount”,在以下过程中将对该类的方法进行测试。

创建单元测试

系统必备:按照准备演练过程中的步骤执行操作。

创建单元测试

  1. 在解决方案资源管理器中,双击 Bank 项目中的 Class1.cs 文件。

    这将打开要查看和编辑的源文件。

  2. 在 Class1.cs 文件的“BankAccount”类中,滚动到“Debit()”方法。

  3. 右击“Debit()”方法,然后选择“创建单元测试”。

    随即出现“创建单元测试”对话框。

    在“当前选择”下,树结构将显示保存“BankAccount”类的程序集的类和成员层次结构。使用此页可以为选定的任何成员生成单元测试,并可以选择要在其中放置生成的单元测试的测试项目。

    在该树结构中,只选择了“Debit()”方法。将其保留选定状态并选择“Credit()”方法。

  4. 对于“输出项目”,请选择“创建新的 Visual C# 测试项目”。

  5. 单击“设置”。

    随即出现“测试生成设置”对话框。在“命名设置”下,可以更改测试文件、测试类和测试方法在生成时的命名方式。在“常规”下,可以更改测试生成的其他方面。将这些设置保留为默认值,然后单击“确定”。

  6. 在“创建单元测试”对话框中单击“确定”。

    随即出现“新建测试项目”对话框。

  7. 接受默认名称,然后单击“创建”。

    这将创建一个名为 TestProject1 的项目,该项目将显示在解决方案资源管理器中。

    一个名为 BankAccountTest.cs 的文件添加到 TestProject1 中,该文件包含一个测试类。该类中填充有一个 TestContext 属性以及测试“Debit()”和“Credit()”方法的方法。

    说明:

    将自动为每个测试方法分配“TestMethod()”属性。每个测试都与要测试的测试代码中的一个方法相对应。测试方法保存在已分配“TestClass()”属性的测试类中。

  8. 在 BankAccountTest.cs 中,指定要测试的变量的值。滚动到“DebitTest”方法,在此可以看到 // TODO 行,它们指示要设置的变量。应使用什么值?若要回答此问题,必须知道应用程序运行时要使用的值。我们将在下面的步骤中确定这些值。

  9. 打开 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)。

  10. 在 BankAccountTest.cs 文件中,滚动到“DebitTest”方法。

  11. 设置下列值:

    BankAccount target = new BankAccount("Mr. Bryan Walton", 11.99);
    double amount = 11.22;
    
  12. 在 BankAccountTest.cs 文件中,对“CreditTest”方法重复以上所做的更改。

  13. 保存 BankAccountTest.cs 文件。

您已创建了一个源代码文件,其中包含 Bank 项目的测试。现在可以对 Bank 项目的代码运行“BankAccountTest”类中的测试了。

运行和自定义单元测试

系统必备:执行创建单元测试过程中的步骤。

运行和自定义单元测试

  1. 打开“测试视图”窗口。

  2. 右击“DebitTest”,再单击“运行选定内容”。

    如果“测试结果”窗口尚未打开,则它现在打开。“DebitTest”测试运行。

    在“测试结果”窗口的“结果”列中,当测试运行时,测试状态将显示为“正在运行”。测试运行完成后,测试的结果将更改为“没有结论”。

  3. 在“测试结果”窗口中双击表示测试的行。

    这将打开“测试结果详细信息”页,其中包含有关测试结果的信息。

  4. 请注意,“测试结果详细信息”页显示以下错误消息:“Assert.Inconclusive 失败。无法验证不返回值的方法。”若要创建成功的测试,请先查找并评估此“Assert”语句。

  5. 若要查找包含“Assert”语句的测试方法,请打开 BankAccountTest.cs 文件并滚动到“DebitTest()”方法。

  6. Assert 语句是“DebitTest”方法中的最后一行。它显示如下内容:

    Assert.Inconclusive("A method that does not return a value cannot be verified.");
    

    注释掉此 Assert 语句。

  7. 如果现在运行测试,则会得出“已通过”结果,但这仅仅是因为它没有对任何内容进行测试。必须添加对预期的结果进行测试的代码。向“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”方法的精确性。

运行单元测试并修复代码

系统必备:执行运行和自定义单元测试过程中的步骤。

运行单元测试并修复代码

  1. 再次运行 Debit 测试:在文件 BankAccountTest.cs 中,右击“DebitTest()”方法,然后单击“运行测试”。

    在“测试结果”窗口的“结果”列中,当测试运行时,测试状态将显示为“正在运行”。测试运行完成后,测试的结果将更改为“未通过”。

  2. 在“测试结果”窗口中双击表示测试的行。

    这将打开“测试结果详细信息”页,其中显示以下错误消息:“Assert.AreEqual 失败。预期值 <0.77> 和实际值 <23.21> 之间的差不应大于 <0.05>”。这些数字似乎表明数学运算不正确。由于“BankAccountTest”类的“DebitTest”方法测试“BankAccount”类的“Debit”方法,所以从检查“Debit”方法开始。

  3. 打开 Class1.cs 文件并滚动到“Debit”方法。

  4. 请注意以下赋值:

    m_balance += amount;
    

    此赋值向余额增加金额,在“Debit”方法中,应当减去赋值。将此行更改为:

    m_balance -= amount;
    
  5. 再次运行“Debit”测试。

    在“测试结果”窗口的“结果”列中,将为“DebitTest”显示“已通过”。

    说明:

    更改源代码后不必重新生成项目,因为运行测试时会生成项目而不进行提示。

您创建了一个可以运行的单元测试,并通过它查找和修复了代码中的错误。

为私有方法创建和运行单元测试

系统必备:执行运行单元测试并修复代码过程中的步骤。

为私有方法创建和运行单元测试

  1. 打开 Bank 项目中的 Class1.cs 文件。

  2. 右击“FreezeAccount()”方法,然后选择“创建单元测试”。

    随即出现“创建单元测试”对话框。

    在显示的树结构中,只有“FreezeAccount()”方法处于选定状态。

  3. (可选)单击“筛选器”,然后清除“显示非公共项”。注意,“FreezeAccount()”方法已从 BankAccount 类的子方法列表中移除。再次单击“筛选器”,然后选择“显示非公共项”以重新显示“FreezeAccount()”方法。

  4. 确保“FreezeAccount()”方法处于选中状态,然后单击“确定”。

    此时将新建一个名为 Bank.accessor 的专用访问器文件。该文件中包含特殊的访问器方法,测试使用这些方法间接调用 BankAccount 类中的私有方法。在解决方案资源管理器的“测试引用”文件夹中可以看到这个新文件。

  5. 打开 BankAccountTest.cs 文件并滚动到“FreezeAccountTest()”方法。

  6. 更改“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.");
    }
    
  7. 运行“FreezeAccountTest”测试。

    在“测试结果”窗口的“结果”列中,最终测试状态显示为“已通过”。该结果与预期结果一致,原因是测试在调用“FreezeAccount()”方法冻结帐户之后调用了“Credit()”方法。

您已经添加了一个私有方法,为其创建了新的单元测试并运行了该测试。可以对 balance 变量使用其他边界值(如 15.00)来多次运行该测试。

后续步骤

对程序集中的代码运行测试时,可以通过收集代码覆盖率数据来查看正在测试的项目代码部分。有关更多信息,请参见演练:运行测试并查看代码覆盖率

可以在命令行中(而不是在 Visual Studio 中)运行测试。有关更多信息,请参见演练:使用命令行测试实用工具

请参见

任务

单元测试示例

概念

单元测试框架

报告的测试结果