将刚导出的PostAQuestionInJazzDotNet.java放入cases文件夹,data文件夹用来存储脚本中需要用到的数据,map文件夹中用来存储脚本中用到的对象的属性信息,lib文件夹中用来放置所需要的依赖jar包。目前需要将selenium web driver相关的jar包放入到lib中,并且加入到build path中。
打开PostAQuestionInJazzDotNet.java,修复编译错误,例如将包名修改为cases,如图4:
▲图4 通过Selenium IDE导出的JUnit格式的java脚本
修复编译错误后的脚本应该已经可以运行,但基于以下原因,我们需要对脚本重构:
a. 录制出来的脚本易读性一般。
b. 数据/对象属性与测试逻辑混为一体,不便于维护。
c. 导出的脚本是基于JUnit的,我们需要修改为TestNG的。
3. 重构脚本
3.1 将测试数据从测试逻辑中分离,也即参数化数据。
我们采用csv作为存储数据的格式,如图5所示:(截图为通过Excel打开的显示的样式)
▲图5 以CSV格式来存储数据
第一行为每个数据项指定一个逻辑的名字,以逗号分隔,从第二行起,在对应的数据列中填上脚本中要用到的数据值,支持多行数据的存储,便于以后实现数据驱动。
创建DataHelper类,用于从数据文件中获取数据。
其中包含的主要方法有:
initFullAppData,用于将数据读入内存,代码片段如下:
▲图6 initFullAppData代码片段
getAppData,用于根据数据项的逻辑的名字读取出某行的值,代码片段如下:
▲图7 getAppData代码片段
在脚本中可以这样使用:
在setUp方法中调用:DataHelper.initFullAppData(this, projectPath, cassName);
然后在其他测试方式中可以直接通过DataHelper.getAppData("PostAQuestionInJazzDotNet_data:JazzURL",1);获得数据值,其中第一个参数是数据项的全名,第二个参数是该数据项的第几个值(这点是为了考虑做iteration,也即数据驱动测试所设置的)
3.2 将web上的元素的属性值从测试逻辑中分离
这里需要了解一下Selenium如何查找定位web元素。
By.id
By.cssSelector
By.linkText
By.name
By.xpath
By.partialLinkText
通过以上的locator可以看出来Selenium支持利用多种属性定位,那我们需要将对象的属性存储在独立的文件中,便于维护和重用,因此我们以如下的xml的格式来存储元素的属性值,如下图:
▲图8 用XML格式来存储对象属性
其中,例如 LoginLink为对象的逻辑名称,可以由测试人员自己定义;propertyName来指定用何种方式来定位元素,可选的值包括:id, name, link, dom, xpath, css, partiallink;value用来存储属性值。
创建AutoObjectFactory类来管理对象属性文件,代码片段如下:
▲图9 AutoObjectFactory代码片段
在脚本中可以这样使用:
在case中定义:private AutoObjectFactory factory = AutoObjectFactory.createInstance(
"PostAQuestionInJazzDotNet_map.xml", projectPath
+ File.separator + "map");
然后在测试方法中通过:WebElement element = factory.getWebElement("PostAQuestionInJazzDotNet_map:userName", driver, defaultTimeOut);获得对象,然后调用相应的方法对其进行操作,例如:
element.sendKeys(DataHelper.getAppData("PostAQuestionInJazzDotNet_data:userName",1));
通过两步分离之后,脚本结构更加清晰,如下图所示:
▲图10 两步分离之后的脚本的代码片段
看似测试数据与测试逻辑的分离,对象属性与测试逻辑的分离,有些额外的efforts要做,但从长远来说对于脚本的重用,维护都有很多益处,例如:对象和数据可以在多个脚本之间公用,如果对象或者数据有变化,只需要在其独立文件中修改,修改后的内容自然得以在引用它的多个脚本中生效。