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

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

提示

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

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

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

  • 打开一个现有项目。

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

  • 对代码运行这些测试。

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

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

系统必备

准备演练

准备演练

  1. 打开 Visual Studio 2010 高级专业版。

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

    此时将出现**“新建项目”**对话框。

  3. 在**“已安装的模板”下单击“Visual C#”**。

  4. 在应用程序类型的列表中单击**“类库”**。

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

    提示

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

    将创建新的 Bank 项目并将其显示在解决方案资源管理器中,而且将在代码编辑器中打开 Class1.cs 文件。

    提示

    如果代码编辑器中未打开 Class1.cs 文件,请在解决方案资源管理器中双击文件 Class1.cs 将其打开。

  6. 用于创建单元测试的示例项目中复制源代码。

  7. 用于创建单元测试的示例项目中的代码替换 Class1.cs 的原始内容。

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

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

创建单元测试

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

创建单元测试

  1. 如果代码编辑器中未打开 Class1.cs 文件,请在解决方案资源管理器中双击 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. 若要了解 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)。

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

  11. 设置下列值:

    BankAccount target = new BankAccount("Mr. Bryan Walton", 11.99);
    double amount = 11.22;
    
  12. 在**“CreditTest”**方法中,将“Mr. Bryan Walton”和 11.99 添加到新的 BankAccount 中。

  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 中)运行测试。 有关更多信息,请参见演练:使用命令行测试实用工具

如果正在使用 Visual Studio 2010 旗舰版,则可以使用单元测试创建负载测试以隔离压力和性能问题。

演练:创建并运行包含单元测试的负载测试

请参见

任务

用于创建单元测试的示例项目