单元测试基础

本主题描述编写基本知识,和运行单元测试Visual Studio测试管理器。 它包含下列部分:

Unit testing overview

  • Quick starts

The MyBank Solution example

Creating the unit test projects

Writing your tests

Running tests in Test Explorer

  • Running and viewing tests from the Test Explorer toolbar

  • Running tests after every build

  • Filtering and grouping the test list

Debugging unit tests

Additional tools for unit tests

  • Generating application code from tests

  • Generating multiple tests by using data driven test methods

  • Analyzing unit test code coverage

  • Isolating unit test methods with Microsoft Fakes

概述的单元测试

Visual Studio测试Explorer设计支持合并 测试 在其软件开发实践单元的开发人员和团队。 测试帮助的单元通过验证确保您的程序的正确性应用程序代码执行所按预期执行。 在单元测试,您分析程序的功能以查看可测试作为单个单元的分离可测试的行为。 使用一个 单元测试框架的 创建测试这些行为,并将报告这些测试的结果。

它是您的软件开发工作流时,的组成部分单元测试具有最大的影响。 当您编写函数或其他块验证代码行为以响应标准、边界和不正确的大小写输入数据,并且,验证代码所做的任何显式或隐式假设的应用程序代码中,可以创建单元测试。 在软件开发实践,在编写代码,因此,可以使用该单元测试作为设计文档和功能的功能规范之前,称为 测试驱动的开发,将创建单元测试。

测试资源管理器提供灵活,并有效方法运行单元测试并查看其在Visual Studio的结果。 Visual Studio安装测试托管代码和本机代码的Microsoft单元结构。 测试资源管理器还可以运行第三方,并打开源单元测试实现了测试资源管理器附加程序接口的结构。 可以通过Visual Studio扩展管理器和Visual Studio库添加其中许多结构。 请参见如何:安装第三方单元测试框架

测试资源管理器视图中显示已通过的所有测试,或测试,失败,只未运行,也会跳过了。 在所有视图可以筛选测试通过与在搜索框中的文本在全局级或通过选择某个预定义的筛选器。 可以运行所有选择在+任何+时间测试。 当您使用 Visual Studio 旗舰版时,可以运行在每次生成后自动测试。 测试运行的结果十分清单中通过或失败栏位于资源管理器窗口的顶部。 当选择测试时,测试方法结果的详细信息显示。

Hh694602.collapse_all(zh-cn,VS.110).gif快速启动

有关单元测试介绍指导您直接向代码,请参见以下主题之一:

MyBank解决方案示例

在本主题中,我们使用例如调用 MyBank 的一个虚构的应用程序的开发。 您不需要实际代码按照本主题中的说明。 测试方法在C#中,并显示使用测试托管代码的Microsoft单元结构,但是,概念轻松地传输到其他语言和结构。

MyBank 解决方案

我们的一个设计的第一次尝试 MyBank 应用程序中包含到个银行表示一个个人帐户及其事务的帐户元素和表示函数聚合和管理个人帐户的数据库元素。

我们将创建包含两个项目的一个 MyBank 解决方案:

  • Accounts

  • BankDb

我们在的"设计 Accounts 项目的第一次尝试包含选件类包含有关帐户、指定任何类型的帐户常见功能,也将和提取资产从该帐户的接口以及从表示一个支票帐户的接口派生的选件类的基本信息。 我们通过创建以下源文件以开始帐户项目:

  • AccountInfo.cs 定义帐户的基本信息。

  • IAccount.cs 定义一个帐户的标准 IAccount接口,包括方法使和提取帐户中的资产和检索帐户余额。

  • CheckingAccount.cs 包含实现一个支票帐户的 IAccounts 接口的 CheckingAccount 选件类。

我们从体验知道从一个支票帐户的取款必须执行的一点是,确保提取的此数量小于帐户余额小于。 为了重写在 CheckingAccount 的 IAccount.Withdaw 方法与检查此条件的方法。 该方法可能如下所示:

public void Withdraw(double amount)
{
    if(m_balance >= amount)
    {
        m_balance -= amount;
    }
    else
    {
        throw new ArgumentException(amount, "Withdrawal exceeds balance!")
    }
}

既然有一些代码,是测试的时间。

创建单元测试项目

单元测试项目通常反射单个代码项目的结构。 在MyBank示例中,将添加两个单元测试项目命名 AccountsTests 和 BankDbTests 到 MyBanks 解决方案。 测试项目名称是任意的,但是,采用标准命名约定是一个好办法。

若要添加单元测试项目的解决方案:

  1. *** 文件 *** 菜单中,选择 新建 然后选择 项目 (键盘Ctrl + shift + N)。

  2. "新建项目"对话框中,展开 *** 安装 *** 节点,选择要用于测试项目,然后选择 测试的语言。

  3. 若要使用某个Microsoft单元测试框架,从项目模板列表中选择 *** 单元测试项目 ***。 否则,选择单元的项目模板测试要使用的结构。 若要测试此示例 Accounts 项目中,将项目命名 AccountsTests。

    警告

    并非所有的第三方和开放源代码单元测试框架提供Visual Studio项目模板。有关创建项目的信息,请参考框架文档。

  4. 在单元测试项目,添加对代码项目下在本示例中,为测试帐户项目。

    若要创建对代码项目:

    1. 在解决方案资源管理器中选择项目。

    2. 项目 菜单中,选择 *** 添加引用 ***

    3. 在引用管理器对话框中,打开 *** 解决方案 *** 节点并选择 *** 项目 ***。 选择代码项目名称并关闭对话框。

每个单元测试项目包含反射选件类的名称在代码项目的选件类。 在本示例中,AccountsTests 项目将包含以下选件类:

  • AccountInfoTests 选件类包含单元测试 AccountInfo 选件类的方法。BankAccount 项目

  • CheckingAccountTests 选件类包含单元测试 CheckingAccount 选件类的方法。

编写测试

该单元测试使用的结构,Visual Studio Intellisense在创建单元将引导您完成测试代码项目。 若要运行测试资源管理器中,大多数结构要求您将特定特性标识单元测试方法。 框架还提供一种通常通过断言语句或方法属性设置为指示测试方法是否已通过或未通过。 其他特性标识在选件类初始化的选项设置方法,因此,在每个测试运行的方法和反汇编方法之前,在每个测试方法后,因此,在销毁之前选件类。

AAA (使,操作,断言)模式是一种常见写作方式单元测试方法中。

  • 单元测试的 线 部分测试方法初始化对象并将传递给方法的测试数据的值。

  • 操作 部分调用方法下测试与排列的参数。

  • 断言 部分验证方法的事件下测试无法按预期方式工作。

若要测试此示例 CheckingAccount.Withdraw 方法,我们可以编写两个测试:验证方法的标准行为与该平衡验证取款更多的一个和一个将失败。 在 CheckingAccountTests 选件类,我们添加以下方法:

[TestMethod]
public void Withdraw_ValidAmount_ChangesBalance()
{
    // arrange
    double currentBalance = 10.0;
    double withdrawal = 1.0;
    double expected = 9.0;
    var account = new CheckingAccount("JohnDoe", currentBalance);
    // act
    account.Withdraw(withdrawal);
    double actual = account.Balance;
    // assert
    Assert.AreEqual(expected, actual);
}

[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void Withdraw_AmountMoreThanBalance_Throws()
{
    // arrange
    var account = new CheckingAccount("John Doe", 10.0);
    // act
    account.Withdraw(1.0);
    // assert is handled by the ExcpectedException
}

请注意 Withdraw_ValidAmount_ChangesBalance 使用显式 Assert 语句来确定测试方法是通过还是失败,则,而 Withdraw_AmountMoreThanBalance_Throws 使用 ExpectedException 属性确定测试方法的成功。 在背后,单元测试框架换行测试在try/catch语句的方法。 在大多数情况下,因此,如果捕获到异常,测试方法失败,并且异常被忽略。 因此,如果指定的,将引发异常。ExpectedException 特性使测试方法传递。

有关测试框架的Microsoft单元测试的更多信息,请参见以下主题之一:

运行测试资源管理器

在生成测试项目时,测试将出现测试管理器。 如果测试资源管理器中不可见,选择在Visual Studio的菜单上的 测试,选择 *** Windows ***,然后不选择 *** 测试资源管理器 ***

单元测试资源管理器

当您运行的是,编写,并在 *** 未通过的测试 ****** 通过测试 ****** 跳过测试 *** 和 ***** 未运行测试 *****组中重新运行测试,测试资源管理器默认视图显示结果。 可以选择组标题打开显示其所有在该组中测试的视图。

Hh694602.collapse_all(zh-cn,VS.110).gif运行和查看从测试资源管理器工具栏测试

测试资源管理器工具栏帮助您发现,组织,并运行测试所感兴趣。

从测试资源管理器工具栏运行测试

可以选择 *** 运行任何 *** 运行所有测试或选择 运行 选择一个子集的测试运行。 在运行测试设置,测试的摘要执行出现在测试资源管理器窗口的底部之后。 选择一个测试查看详细信息该测试在底部窗格中。 从上下文菜单(键盘选择 *** 打开"测试 *** :)显示选定的源代码的F12测试。

Hh694602.collapse_all(zh-cn,VS.110).gif运行在每次生成后测试

警告

在每次生成后,在最终的Visual Studio仅支持运行单元测试。

生成后运行

若要运行单元测试,每本地生成,选择标准菜单后的 测试,选择在测试资源管理器工具栏中 *** 运行在编译之后测试 ***

Hh694602.collapse_all(zh-cn,VS.110).gif筛选和分组测试列表

当您具有大量测试时,可以输入测试Explorer搜索框按指定数目的筛选列表。 通过选择限制为的筛选器事件从筛选器更列表。

搜索筛选器类别

测试资源管理器的分组按钮

对组按类别选择该测试,*** 组 *** 按钮。

有关更多信息,请参见用测试资源管理器运行单元测试

调试单元测试

可以使用测试资源管理器时启动调试会话测试。 逐句通过您的Visual Studio调试器的代码无缝获取您在该单元之间来回测试,并且该项目中。 开始调试:

  1. 在Visual Studio编辑器中,将一个或多个断点测试要调试的方法。

    备注

    由于测试方法可以按任意顺序运行,请在要调试的所有测试方法中的断点。

  2. 在测试资源管理器中,选择测试方法从快捷菜单中选择 *** 调试选择测试 ***

有关调试器的更多信息,请参见 使用 Visual Studio 进行调试

为单位的其他工具测试

Hh694602.collapse_all(zh-cn,VS.110).gif生成应用程序代码从测试

如果您编写测试,在编写您的项目代码中,可以使用Intellisense生成选件类和方法在项目代码。 编写在调用选件类或方法要生成的测试方法的语句,然后打开Intellisense菜单调用下方。 如果调用是为新的选件类的构造函数,从菜单中选择 *** 生成新类型 *** 并在向导插入选件类在代码项目。 如果调用是方法,从Intellisense菜单选择 *** 生成新方法 ***

生成方法存根 Intellisense 菜单

Hh694602.collapse_all(zh-cn,VS.110).gif生成多个测试可使用数据驱动测试方法

备注

这些过程仅适用于测试方法通过使用Microsoft单元测试中编写托管代码的结构。如果使用不同的机制,请参考等效功能的framework文档。

数据驱动的测试方法 可用于对照取值范围在一个单元的测试方法。 若要创建数据驱动的单元测试方法,用指定数据源和表包含变量值要测试的 DataSource 属性的方法。 使用 TestContext.DataRow[ColumnName] 索引器,在方法体中,将行值赋给变量。

例如,假设我们添加一个不必要的方法添加到名为 AddIntegerHelper的 CheckingAccount 选件类。 AddIntegerHelper 添加两个整数。

创建数据驱动测试 AddIntegerHelper 方法,我们首先创建一个Access数据库名为 AccountsTest.accdb 和表名为 AddIntegerHelperData。 AddIntegerHelperData 表定义列指定和列添加的第一和第二个操作对象指定预期结果。 我们使用适当的值加载若干行。

    [DataSource(
        @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Projects\MyBank\TestData\AccountsTest.accdb", 
        "AddIntegerHelperData"
    )]
    [TestMethod()]
    public void AddIntegerHelper_DataDrivenValues_AllShouldPass()
    {
        var target = new CheckingAccount();
        int x = Convert.ToInt32(TestContext.DataRow["FirstNumber"]);
        int y = Convert.ToInt32(TestContext.DataRow["SecondNumber"]); 
        int expected = Convert.ToInt32(TestContext.DataRow["Sum"]);
        int actual = target.AddIntegerHelper(x, y);
        Assert.AreEqual(expected, actual);
    }

一个字符串的方法为每行在表中一次运行。 如果任何一个迭代失败,测试资源管理器报告方法的一个测试失败。 方法的测试结果详细信息窗格显示了数据的每一行都通过或失败状态方法。

有关更多信息,请参见如何:创建数据驱动的单元测试

Hh694602.collapse_all(zh-cn,VS.110).gif分析单元测试代码复盖率

备注

单元测试代码复盖率为本机可用,而托管语言和所有单元测试可由运行单元测试框架的。

您可以确定使用Visual Studio代码复盖率工具,由您的单元实际测试的数量您的产品代码。 在解决方案中运行所选测试的代码复盖率或在所有测试。 代码复盖率结果"窗口显示由直线、函数、选件类、命名空间和模块执行的百分比的块产品代码。

若要运行代码复盖率为测试在解决方案的方法,

  1. 选择在Visual Studio的菜单上的 *** 测试 *** 然后选择 *** 分析代码复盖率 ***

  2. 选择这些命令之一:

    1. *** 选择测试 *** 运行所选测试资源管理器的测试方法。

    2. *** 所有测试 *** 运行该解决方案中的所有测试方法。

复盖率结果将显示在"代码复盖率结果"窗口。

代码覆盖率结果

有关更多信息,请参见 使用代码覆盖率确定所测试的代码量

Hh694602.collapse_all(zh-cn,VS.110).gif隔离单元测试与Microsoft伪造品的方法

备注

Microsoft伪造品只能在最终的Visual Studio。Microsoft伪造品只能与测试方法。通过单元测试中编写托管代码的结构。

问题

单元测试方法在验证内部代码的焦点在函数可能难以编写,在方法下测试调用引入外部依赖项的功能。 例如,CheckingAccount 示例选件类的方法可能应调用 BankDb 元素更新主程序数据库。 我们可以重构显示的 CheckingAccount 选件类以下操作:

class CheckingAccount : IAccount
{
    public CheckingAccount(customerName, double startingBalance, IBankDb bankDb)
    {
        m_bankDb = bankDb;
        // set up account
    }

    public void Withdraw(double amount)
    {
        if(m_balance >= amount)
        {
            m_balance = m_MyBankDb.Withdraw(m_accountInfo.ID, amount);
        }
        else
        {
            throw new ArgumentException(amount, "Withdrawal exceeds balance!")
        }
    }

    private IBankDb m_bankDb = null;
    // ...

单元测试将此 CheckingAccount.Withdraw 方法现在可以因而导致调用 m_bankDb.Withdraw。 数据库或网络连接可能会丢失或在数据库的权限可能是错误的。 在 m_bankDB.Withdraw 的一个通过调用将导致测试未与其内部代码相关的原因失败。

Microsoft伪造品解决方案

Microsoft伪造品创建包含选件类和方法,可以使用为单位选件类用测试方法产生依赖的程序集。 在生成的伪造品模块的替代选件类声明一个方法和一个委托每个公共方法的在目标元素。 在测试方法中,您要测试的方法实现委托创建依赖项的确切行为调用。

在本示例中,我们可以创建 BankDb 项目的伪造品程序集,然后使用由伪造品生成的,并从 IBankDb 接口派生取消交互引起的不确定性与数据库的 StubIBankDb 选件类。 Withdraw_ValidAmount_ChangesBalance 的一个modifed版本测试方法然后如下所示:

[TestMethod]
public void Withdraw_ValidAmount_ChangesBalance()
{
    // arrange
    double currentBalance = 10.0;
    double withdrawal = 1.0;
    double expected = 9.0;

    // set up the Fakes object and delegate
    var stubBankDb = new MyBank.Stubs.StubIBankDb();
    stubBankDb.WithdrawDoubleDouble = (id, amount) => { return 9.0; }
    var account = new CheckingAccount("JohnDoe", currentBalance, stubBankDb);

    // act
    account.Withdraw(withdrawal);
    double actual = account.Balance;

    // assert
    Assert.AreEqual(expected, actual);
}

在测试方法中的此行:

stubBankDb.WithdrawDoubleDouble = (id, amount) => { return 9.0; }

使用lamba表达式,实现 Withdraw 方法的伪造品委托。 stubBankDb.Withdraw 方法调用委托和因此总是返回指定的量,使测试方法可靠验证 Accounts 方法的行为。

更多有关Microsoft伪造品

Microsoft程序集使用两种方法来创建替代选件类:

  1. 存根 生成从目标依赖项选件类的父接口派生的替代选件类。 存根方法可以用目标选件类的公共虚方法进行替换。

  2. 牵制的填充 使用运行时检测对目标方法对非虚方法的替代填充方法。

在这两种方法,则使用生成的委托调用依赖项方法指定要在测试方法需的行为。

有关更多信息,请参见 用 Microsoft Fakes 隔离测试代码