作为自动化测试的一种脚本技术,数据驱动技术在10几年前已经有人提出,并且沿用到现在。Nunit作为C#开发下的一种常用的单元测试框架,也是被广泛使用。但是对于单元测试,很多时候都是硬编码,虽然说用Nunit编写单元测试代码是挺廉价的,但是为什么不让自己的工作更加轻松,脚本更加灵活呢?

我把单元测试的数据放到单独的XML文件里面,测试运行的时候就读取XML数据然后进行测试。由于我想做一个轻量级的单元测试,所以并没有把很多判断控制的语句写到一个单元测试里面,而是把有不同行为的测试写到一个脚本里面。例如期望结果都是成功的一类测试就写到一个脚本,包含同样错误的测试就写到另外一个脚本,尽管这样看起来并不是很高明,但是对于我的工作来说这是足够的了。

首先是XML文件的结构,其实很简单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version="1.0" encoding="utf-8" ?>
<TestData>
  <TestXMLD>
    <TestCase_1 isEnable="True">
      <UserID>111</UserID>
      <FriendID>222</FriendID>
      <AlbumCounterExpected>True</AlbumCounterExpected>
      <AlbumCounterOutput>User album counter should greater equal than 0, the actual value is </AlbumCounterOutput>
      <PhotoCounterExpected>True</PhotoCounterExpected>
      <PhotoCounterOutput>User photo counter should greater equal than 0, the actual value is </PhotoCounterOutput>
      <ReturnIDExpected>True</ReturnIDExpected>
      <ReturnIDOutput>Return user ID is not valid, the actual value is </ReturnIDOutput>
    </TestCase_1>
    <TestCase_2 isEnable="True">
      <UserID>222</UserID>
      <FriendID>111</FriendID>
      <AlbumCounterExpected>True</AlbumCounterExpected>
      <AlbumCounterOutput>User album counter should greater equal than 0, the actual value is </AlbumCounterOutput>
      <PhotoCounterExpected>True</PhotoCounterExpected>
      <PhotoCounterOutput>User photo counter should greater equal than 0, the actual value is </PhotoCounterOutput>
      <ReturnIDExpected>True</ReturnIDExpected>
      <ReturnIDOutput>Return user ID is not valid, the actual value is </ReturnIDOutput>
    </TestCase_2>
  </TestXMLD>
</TestData>

根节点是TestData,它的子结点是TestXMLD,这个节点是跟我的单元测试方法同名的。这个节点下面有2个子结点,分别是两套测试的数据,每套测试的数据分别包含了测试运行时候用到的数据,期望结果以及测试不能通过时候所要显示的错误提示。而且每套数据都包含一个isEnable的属性,如果设为False,那么测试运行的时候就不跑这一条数据。

测试的方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
[TestMethod]
public void TestXMLD()
{
     XmlDocument xd = new XmlDocument();
     xd.Load(@"TestData\AlbumService.xml");
     string testDataNode = System.Reflection.MethodBase.GetCurrentMethod().Name;
     XmlNode testdata = xd.SelectSingleNode("/TestData/" + testDataNode);
     XmlNodeList testdatas = testdata.ChildNodes;
     foreach (XmlNode datanode in testdatas)
     {
         //Get the enabled test data
         bool isEnable = Convert.ToBoolean(datanode.Attributes.GetNamedItem("isEnable").InnerText);
         if (!isEnable)
         {
             break;
         }
         //Prepare test data.
         int userId = Convert.ToInt32(datanode.SelectSingleNode("UserID").InnerText);
         int FriendID = Convert.ToInt32(datanode.SelectSingleNode("FriendID").InnerText);
         bool AlbumCounterExpected = Convert.ToBoolean(datanode.SelectSingleNode("AlbumCounterExpected").InnerText);
         string AlbumCounterOutput = datanode.SelectSingleNode("AlbumCounterOutput").InnerText;
         bool PhotoCounterExpected = Convert.ToBoolean(datanode.SelectSingleNode("PhotoCounterExpected").InnerText);
         string PhotoCounterOutput = datanode.SelectSingleNode("PhotoCounterOutput").InnerText;
         bool ReturnIDExpected = Convert.ToBoolean(datanode.SelectSingleNode("ReturnIDExpected").InnerText);
         string ReturnIDOutput = datanode.SelectSingleNode("ReturnIDOutput").InnerText;
 
         //Assertion
         UserAlbums userAlbum = PSProvider.Instance.GetUserAblums(userId, FriendID);
         Assert.AreEqual(AlbumCounterExpected, userAlbum.AlbumCount &gt;= 0, AlbumCounterOutput + userAlbum.AlbumCount);
         Assert.AreEqual(PhotoCounterExpected, userAlbum.PhotoCount &gt;= 0, PhotoCounterOutput + userAlbum.PhotoCount);
         Assert.AreEqual(ReturnIDExpected, userAlbum.User.Id == userId, ReturnIDOutput + userAlbum.User.Id);
     }
 }

首先把XML文件load进XMLDOCUMENT对象中,然后用反射获取该方法的名字,因为方法名也是测试数据节点的名称。然后选中改方法的测试数据的节点。把所有的子结点放到一个XMLNODELIST对象里面,对这个对象进行枚举,然后就开始真正的工作了。如果isEnable是True,那么就读取该节点的下面的数据然后运行测试;如果为False就跳过该条测试数据,跳到下一条。

一个脚本对应一套测试数据,实际操作起来是很不好的,如果需要增加测试数据的话成本比较高,数据驱动的特点就是测试数据和脚本的分离,使得测试数据容易维护。其实测试重要的是数据而不是承载这些数据的脚本。应该把关注点放到设计一些好的测试数据上面。

Share and Enjoy:
  • RSS
  • Google Bookmarks
  • Digg
  • del.icio.us
  • Facebook
  • 豆瓣
  • 豆瓣九点
  • FriendFeed
  • LinkedIn
  • Live
  • Ping.fm
  • QQ书签
  • Twitter

Related posts:

  1. 单元测试中的常用测试模式
  2. 在VSTS中创建Web Test的插件
  3. PEX-.NET自动化白盒测试工具的介绍(1)
  4. 测试代码重构实例