技术开发 频道

使用VS Team Edition进行单元测试

  【IT168 专稿】Microsoft Visual Studio Team System集成了多种功能,这些功能用于创建高质量代码。其中一项功能用于实现单元编码测试。执行单元测试能够实现测试驱动开发,另一项有用的功能是测试私有方法。在本文中,首先从测试驱动开发技术开始讲解,因为这是敏捷开发人员所提倡的重点。

下一篇:VS Team Edition在其它单元中的测试 

  ·测试驱动开发

  在编写测试代码之前,需要进行单元测试。为此首先必须创建测试项目,然后才能生成测试。为此创建一个空白Visual Studio解决方案,然后添加C#测试项目。项目默认引用Microsoft.VisualStudio.QualityTools.UnitTestFramework程序集,以及包含单元测试的C#文件。单元测试方法和单元测试类使用[TestMethod]和[TestClass]声明,以通知Visual Studio测试框架:它们是测试的方法和类。代码如下所示:

using Microsoft.VisualStudio.TestTools.UnitTesting;
[TestClass]
public class UnitTests
{
    [TestMethod]
    
public void TestMethod1()
    {
        
// TODO: 添加测试逻辑
    }
}

 
  假设正准备开发一个需要测试的计算器类,那么首先按照自定义规则在测试方法中调用计算器方法的代码(名称改为AddTest),代码修改如下:
 
[TestClass]
public class UnitTests
{
     [TestMethod]
    
public void AddTest ()
    {
        
int x = 1; int y = 2;
        
int expected = 3;
        
int actual = MyUtils.Calc.Add(x,y);
        Assert.AreEqual
<int>(expected, actual);
    }
}

  Assert类有一个方法,用于指定某个条件为“是”或“否”。在这种情况下,需要指定与实际结果相等的预期结果。尝试编译该测试会失败,因为还没有编写Calc类。下面必须编写充足的代码才能通过测试。换言之,需要在同一个解决方案中创建一个类库项目,实现Calc类,并从测试项目中引用该类库项目。创建Calc类之后就可以使用从单元测试生成方法说明的功能。即将鼠标在调用Add方法上悬停片刻,就会出现“Generate Method Stub For Add-in MyUtils.Calc”,如图1所示:


图1 从测试生成方法说明

  ·运行测试
 
  编写满足编译器的代码之后,需要运行测试。首先选择单元测试文件,然后单击工具栏的专用按钮运行测试。工具栏还提供了其他选项,例如在调试器中运行测试,或者查看测试结果。执行之后将显示测试失败,如图2所示,因为本例中Visual Studio生成Add方法的默认实现是抛出异常。现在将重新编写代码以通过测试。



图2 测试失败

 

public class Calc
{
    
public static int Add(int x, int y)
    {
        
return x+y;
    }
}

  最后,测试通过,如图3所示,接下来编写下一个测试。


图3 测试成功

  ·测试现有代码

  如果向Calc类中添加一个Subtract方法,然后再右键单击该方法,那么将出现实现对应测试的选项,如图4所示。生成的测试代码基本上与上述AddTest方法相同。


图4  创建单元测试

  ·测试列表和测试运行配置

  还有一种方法是从测试列表运行测试,该方法比之前说明的从专用模式更为常用。在测试项目创建之后自动生成一个扩展名为.vsmdi的文件。这个文件用于保存测试列表。在列表中包含许多关于测试运行的控制选项。


图5  测试管理器

  打开.vsmdi文件将出现如图5显示的测试管理器窗口。管理器创建包含两个测试的UnitTest测试列表。现在可以从测试管理器工具栏运行列表所列的测试。

  创建测试项目时还生成了另一个文件,该文件的扩展名为.testrunconfig,图6显示文件打开之后出现的窗口


图6  测试运行配置

  文件包含影响测试运行方式的配置信息。例如,本例中可以为需要测试的代码定义代码覆盖率。运行测试结果和代码覆盖率信息,如图7所示。


图7.  代码覆盖率


  在图5显示的测试列表执行中,Subtract方法被完全覆盖,但是Add方法却没有。通过Visual Studio Test菜单的Select Active Test Run Configuration选项可以创建并使用多个不同的.testrunconfig文件。


图8  测试目录

  如图8所示,每个测试运行结果都存储在TestResults目录的子目录内对应的扩展名为.trx的文件中。.trx文件名和子目录名默认为计算机名、用户名、测试运行的时间戳,不过它们都可以更改。如图9所示,打开显示.trx文件的测试结果窗口,从中可以看到测试运行结果,还能对测试结果进行管理。


图9  测试结果

建立正确的测试环境
每个测试运行子目录都包含一个Out目录,测试和被测试代码的运行结果都位于其中。它们可能是重要文件,例如执行测试代码相关的部署。例如,在图6中可以找到Deployment选项卡,该选项卡提供了这项功能。另外,更具粒度的方法是在测试方法上使用DeploymentItem属性,该属性需要一个部署项。

[TestClass]
public class MoreUnitTests
{
    [DeploymentItem(
"people.xml")]
    [TestMethod]
    
public string GetPersonIDFromFileTest()
    {
        
string name="Bob";
        
int expected id=1;

        
// GetPersonIDFromFile方法从指定位置读取people.xml
        int actual =
                       MyUtils.DataAccessLayer.GetPersonIDFromFile(name);
        Assert.AreEqual
<int>(expected, actual);
    }
}

另外,还有一些用于帮助建立基于测试或测试组环境的功能。当然,这需要创建和安装数据库,因为数据库是测试方法的交互对象。在图6中可以注意到“Setup And Cleanup Scripts”选项卡,该选项卡提供在一组测试运行之前或之后运行脚本的功能。例如,这些脚本可以建立和清除数据库。另一个实现方法是定义带有特殊标注属性的方法。一对标注了AssemblyInitialize/AssemblyCleanup属性的方法会在测试程序集运行之前/后执行。一对标注了ClassInitialize/ClassCleanup属性的方法会在测试类运行之前/后执行。一对标注了TestInitialize/TestCleanup属性的方法会在测试类的每个测试方法运行之前/后执行。如下代码说明如何在一组测试运行之前建立数据库,之后再将其清除。

[TestClass]
public class YetMoreUnitTests
{
     [ClassInitialize()]
    
public static void Setup(TestContext testContext)
    {
        
// 创建并安装数据库。
    }

     [ClassCleanup()]
    
public static void Teardown()
    {
        
// 清除数据库。
    }

     [TestMethod]
    
public string GetPersonIDFromDatabaseTest()
    {
        
string name="Bob";
        
int expected id=1;

        
// GetPersonIDFromDatabase方法从数据库读取数据。
        int actual =
                     MyUtils.DataAccessLayer.GetPersonIDFromDatabase(name);
        Assert.AreEqual
<int>(expected, actual);
    }
}

  ·测试私有方法

  Visual Studio测试框架还有一个非常有用的功能,就是能够仅通过很小的工作量就能测试私有方法。如图10所示,首先选择一个私有方法,然后从菜单中选择创建单元测试选项。生成的单元测试使用私有访问修饰符,并且使用反射调用私有方法。如下代码示例显示了这个单元测试(带有一些装饰性的改变),不过已经省略了访问修饰符,而采用简单的MyUtils_CalcAccessor.SubtractHelper。


图10  创建私有方法的测试

 

[TestClass]
public class UnitTests
{
    [TestMethod]
    
public void SubtractHelperTest()
    {
        
int x = 0;
        
int y = 0;
        
int expected = 0;
        
int actual;
         actual
= MyUtils_CalcAccessor.SubtractHelper(x, y);
        Assert.AreEqual(expected, actual);
    }
}
0
相关文章