在前面的文章网站测试自动化系统—基于Selenium和VSTT当中,我简单介绍了使用selenium录制测试步骤,以及优化生成的C#代码,对代码使用面向对象的编程理念进行一些封装,以便规避网站界面更动对测试代码所带来的风险。
在网站测试当中(甚至是桌面程序的功能测试),很多情况下,测试步骤是不变,变化的仅仅是测试数据而已。比如说,为了测试网站是否支持国际化,一个正常登录成功的测试,你可能会使用英文的用户名;也可能会使用中文的用户名;甚至还会使用包含一些合法的特殊字符串的用户名。这三个测试用例的操作步骤都是一样,都是输入用户名和密码,然后点击登录按钮,唯一不同的就是用户名和其密码。又比如,为了执行SQL注入或者脚本注入安全性测试,你可能会设计一个针对用户提交评论的通用测试步骤,然而用户评论的内容(包括SQL注入语句或者脚本注入语句)是变化的。 这些测试场景,都可以使用 数据驱动测试来避免重复创建雷同的测试用例,而且数据驱动也给我们提供了很大的弹性,这是因为如果在后续测试过程中发现有些特殊数据被遗漏了,只要更新数据文件就可以了。
VSTT自带了数据驱动测试功能,网上已经有很多文章介绍使用VSTT执行数据驱动的方法了,这里我就不详细说了,如果你不熟悉这个方法的话,请参考MSDN的这篇文章:
http://msdn.microsoft.com/zh-cn/library/ms182527%28VS.80%29.aspx
你可以使用很多数据源来保存数据驱动所需的测试数据,例如access数据库、其他关系型数据库(只要你能提供合法的数据库连接字符串)、csv文件以及Excel文件。
我们在本次测试过程中,采用的是Excel数据源,原因是因为:
1. Excel文件相对于其他数据库来说,更廉价一些,毕竟Excel相对于Access以及其他关系型数据库来说,更便宜(并且易用)一些。
2. Excel文件和csv文件都可以使用Excel来编辑,然而之所以选择Excel文件是因为一个Excel文件可以包括多个工作簿(Worksheet),这个功能方便我们管理测试数据,原因在下文中介绍到。
3. 但是如果你使用Office 2007的话,需要注意,Visual Studio Team Test 2008只支持Excel 2003的格式,因此你在保存文件的时候,千万要保存为Excel 2003的格式,否则VSTT会告诉你它无法访问测试数据源。
为了让例子简单一些,我们还是采用上一篇提到的登录测试的用例,下面是已经改进过的代码:
[TestClass] public class UsersTest { [TestMethod] public void LogOnTest() { var username = "donjuan"; var password = "它是个秘密"; TestLibrary.UserHelper.LogOn(username, password);
Assert.IsTrue(selenium.IsTextPresented(...)); } } |
在上面的代码中,我们已经注意到,username和password是可以变化的测试数据,而LogOn所封装的测试步骤是不会更改的,因此,创建一个Excel 2003的文件用来保存LogOnTest所需的测试数据。这个Excel 2003的文件名就叫UsersTest.xls,在文件中创建一个名为LogOnTest的工作簿(worksheet),LogOnTest工作簿里面有两列,一个叫username, 另一列是password,如下图所示:
接着,上面的测试代码就得改成下面的样子:
[TestClass] public class UsersTest { // 测试数据文件的名称与测试用例所在的类型名相同 [DeploymentItem("UsersTest.xls")] // 每一个测试用例有自己的worksheet,注意第三个字符串,worksheet名后面的 // 美元符号“$” [DataSource( "System.Data.Odbc", @"Driver={Microsoft Excel Driver (*.xls)};DriverId=790;Dbq=UsersTest.xls;DefaultDir=.", "LogOnTest$", DataAccessMethod.Sequential)] [TestMethod] public void LogOnTest() { var username = TestContext.DataRow["username"] as string; var password = TestContext.DataRow["password"] as string; TestLibrary.UserHelper.LogOn(username, password);
Assert.IsTrue(selenium.IsTextPresented(...)); } } |
将Excel文件名命名跟测试用例的类型名相同,是因为方便维护测试代码的时候快速找到对应的测试数据文件。另外,一般也不会把测试数据和测试代码放在同一个文件夹。在VSTT的测试工程文件里,有一个后缀名为.testrunconfig的文件,这个文件用来设置一些测试环境,在“解决方案浏览器(Solution Explorer)”里双击这个文件会打开测试环境配置对话框。左边列表框的第四项“部署(Deployment)”,允许你在测试用例执行之前, 指引VSTT将你指定文件夹里面的所有文件都拷贝到测试用例所在的文件夹里(这个文件夹可以通过TestContext.TestDeploymentDir属性获取到)。这样,测试代码才能在运行的时候,获取到其所需的测试数据。
另外,TestContext.DataRow有一个局限,就是DataRow属性实际上只能表示一个表(我没有成功地在DataRow里面访问到一个以上的表)。但是一般来说,一个测试类型(也就是上面的UsersTest类)都会包含好几个测试用例(类似LogOnTest的单个函数)。如果把一个测试类型的所有测试用例所需要的数据都保存在一个工作簿(worksheet) 里面的话,这个worksheet结果未免过于庞大,难以维护。而如果对每一个测试用例创建一个Excel文件(workbook),最后也导致我们的文件夹有太多的Excel文件,同样难以维护。因此当时我们采取的方案是,对每一个测试类型创建一个Excel文件,每一个需要用到测试数据的测试用例有单独的工作簿(Worksheet),工作簿的名字用测试用例的函数名命名。
这样一来,UsersTest里面新的测试用例类似于下面的形式(注意黄色高亮显示的部分):
[TestClass] public class UsersTest { // 省略其他测试用例 ...
// 测试数据文件的名称与测试用例所在的类型名相同 [DeploymentItem("UsersTest.xls")] // 每一个测试用例有自己的worksheet,注意第三个字符串,worksheet名后面的 // 美元符号“$” [DataSource( "System.Data.Odbc", @"Driver={Microsoft Excel Driver (*.xls)};DriverId=790;Dbq=UsersTest.xls;DefaultDir=.", "PermissionTest$", DataAccessMethod.Sequential)] [TestMethod] public void PermissionTest() { ... } } |
当然啦,也许在后面执行自动化测试用例的时候,有可能因为测试人员的疏忽,导致测试数据和测试代码不同步。发生这种情况的话,也不会有太大影响,因为在前一篇文章中,测试所需的库函数都执行了参数验证,并扔出CaseErrorException向测试人员报告了这个错误。如果不清楚的话,可以再看看下面的代码:
public class UserOperationsHelper { public void LogOn(string username, string password) { // string.Empty留出来为测试目的服务 if (username == null) throw new CaseErrorException(new ArgumentNullException("username")); if (password == null) throw new CaseErrorException(new ArgumentNullException("password"));
... } }
|
一般情况下,批量的自动化测试用例在晚上执行完毕以后,第二天早上,如果时间紧张的话,测试人员可以将所有结果为CaseErrorException的测试用例手工执行一遍。
下一篇在测试代码中硬编码测试数据讲解如何在测试代码中硬编码一些测试数据。