轉載:http://www.51testing.com/html/58/n-3721258.html
先前的自動化測試框架完全是用
Java純手工編寫,核心交易接口代碼、測試腳本、測試數據都進行了抽象和分離,測試報告也是自己設計的html模版輸出,如果項目僅僅本地實施運行,也完全能滿足目前的自動化測試需求。
但為了自動化測試變得更加高大上,並配合公司實施持續集成的工作開展,決定將現有的接口自動化測試框架改造成Maven+TestNG方式,代碼由SVN進行版本管理,項目由Jenkins構建運行。
聽說
TestNG已很久,遺憾一直未嘗試過,但最近學習實踐了一把,這體驗那叫一個字:超爽。
單元測試、注解、組概念、套件、異常、參數化、依賴等等測試思想的加入,讓TestNG服務於接口自動化測試大放異彩。
本篇文章分5部分介紹:
--1 Maven+TestNG的測試框架搭建
--2 使用ReportNG來優化測試報告
--3 測試案例的數據調度設計
--4 使用Jenkins來調度構建運行
--5 讓報告更高大上—Allure報告插件使用
由於篇幅問題,后兩節會放在下一篇。
1、Maven+TestNG的測試框架搭建
准備條件
1、Eclipse及其
Maven插件、TestNG插件的安裝請自行找度娘;
2、本地需安裝Maven,並配置好環境變量;
3、Eclipse中的Maven-settings配置。
創建Maven項目
為了便於管理自動化項目中依賴的jar包、項目構建運行等,我們選擇Maven來創建項目。由於對Maven研究不多,在自動化項目中遇到無法構建引入本地jar包的尷尬,但沒找到解決方法,只好通過避免引入本地jar包來搞定。留待以后再研究怎么引入本地jar包的方法。
Maven項目創建完后,如下目錄結構:
POM文件配置
1、添加testNG的依賴包
有兩種方式:
一種使用下面截圖的方式,當然這種方式依賴於你的Maven插件,有時候搜索不到你想要的依賴包;
還有一種是直接用下面的配置代碼。
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.11</version>
</dependency>
|
添加完成后查看pom文件內容
創建TestNG-Class類
選中 src/test/java目錄,右鍵創建包,
然后在創建好的包上創建TestNG類, 類名:IdAuth,同時添加上@BeforeClass 和 @AfterClass:
代碼中通過@Test注解的就是一個測試案例。
注:如果沒有在pom.xml文件中配置testng的依賴jar包,代碼中會有報錯。
當前對於BeforeClass和AfterClass代碼為空,在后面的內容會使用到。
此時可以使用TestNG來運行類,郵件Run As —> TestNG Test 方式運行,結果如下:
以上就完成了TestNG類創建並使用TestNG 運行測試類。
接下來學習使用Maven來運行項目。
使用Maven運行項目
首先創建testng.xml配置文件(src\test\resources目錄下創建),testng.xml中配置需要運行的TestNG類名(可以配置多個),配置內容如下:
然后用Maven運行項目很簡單,選中項目然后右鍵Run As,會出現很多Maven ***的選項,使用Maven Test選項來運行TestNG類。
當然也可以在DOS窗口中,進入到項目來執行 mvn test。
運行完成后,在項目根目錄中,會出現2個新文件夾:
其中:target是maven生成一些類文件,暫時不用管
test-output是生成testNG類執行的結果:
提供了2種查看執行結果的方式,1個是xml查看,1個是html查看,因為xml友好性不高,咱們直接看html的方式,結果報告中會顯示執行了哪些測試案例,成功數和失敗數,以及每個測試案例執行的時長。
但是,大家看到這個報告的第一感覺是什么?是不是覺得很Low?
我的感覺是簡直Low爆了!!!宇宙第二Low的報告!!!
接下來的內容咱們就來優化報告。
2、使用ReportNG插件來優化測試報告
Pom.xml文件配置更新
1、屬性配置
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<xmlFileName>testng.xml</xmlFileName>
</properties>
|
2、依賴包管理配置
<!-- testNG依賴管理 -->
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.11</version>
</dependency>
<dependency>
<groupId>org.apache.maven.reporting</groupId>
<artifactId>maven-reporting-api</artifactId>
<version>2.0.9</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 依賴Guice -->
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>3.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.uncommons</groupId>
<artifactId>reportng</artifactId>
<version>1.1.4</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<type>maven-plugin</type>
</dependency>
<dependency>
<groupId>com.beust</groupId>
<artifactId>jcommander</artifactId>
<version>1.64</version>
</dependency>
<dependency>
<groupId>net.sourceforge.jexcelapi</groupId>
<artifactId>jxl</artifactId>
<version>2.6.10</version>
</dependency>
|
3、Build及插件配置
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<suiteXmlFiles>
<suiteXmlFile>
src/test/resources/${xmlFileName}
</suiteXmlFile>
</suiteXmlFiles>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<properties>
<property>
<name>usedefaultlisteners</name>
<value>false</value>
</property>
<property>
<name>listener</name>
<value>org.uncommons.reportng.HTMLReporter, org.uncommons.reportng.JUnitXMLReporter</value>
</property>
</properties>
<workingDirectory>target/</workingDirectory>
<forkMode>always</forkMode>
<!-- 解決報告中中文亂碼 -->
<argLine>-Dfile.encoding=UTF-8</argLine>
</configuration>
</plugin>
</plugins>
</build>
|
運行查看報告
用Maven Test運行完成后,可以發現target/目錄下出現新的文件夾
進入這個目錄,打開html/index.html文件可以查看測試報告,如下圖:
這樣的頁面是不是比剛才的美觀了很多。
如果就這樣的報告,肯定不飽滿,那我們需要給測試案例添加測試數據獲取,業務邏輯,斷言以及多個測試類等等。
3、測試案例的參數化設計
參數化設計邏輯圖
項目詳細的目錄結構
ExcelUtils處理類
(代碼未經優化,有些地方可能寫得不合理,請見諒!)
package com.test.pub;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import jxl.Workbook;
import jxl.Sheet;
import jxl.Cell;
public class ExcelUtils {
public static Map <String, HashMap> excelToHashMapByFirstSheet(String fPath, String sheetName){
try{
File fExcel = getExcelFileObj(fPath);
Workbook wb = Workbook.getWorkbook(fExcel);
Sheet sht = wb.getSheet(sheetName);
int rowCount = sht.getRows();
int colCount = sht.getColumns();
Cell cel = null;
Map <String, HashMap> excelContents = new HashMap();
if(rowCount<=2){
System.out.println("無測試案例");
return null;
}else{
//檢查是否存在空行
String rowContents = "";
for(int i=2;i<rowCount;i++){
if(sht.getCell(0, i).getContents().toString().length()==0){
System.out.println("測試案例文件中存在空行");
return null;
}else{
for(int j=0;j<colCount;j++){
rowContents = rowContents + sht.getCell(j, i).getContents().toString();
}
if (rowContents.length()<20){
System.out.println("測試案例文件中存在空行");
return null;
}
}
}
}
//開始讀取內容
for(int rowIndex=2;rowIndex<rowCount;rowIndex++){
HashMap<String, String> rowMap = new HashMap();
String testCaseCode = sht.getCell(0, rowIndex).getContents().toString();
for(int colIndex=1;colIndex<colCount;colIndex++){
rowMap.put(sht.getCell(colIndex, 1).getContents().toString(), sht.getCell(colIndex, rowIndex).getContents().toString());
}
excelContents.put(testCaseCode, rowMap);
}
wb.close();
//HashMap<String, String> tmpMap = new HashMap();
//tmpMap.put("count", "" + (rowCount-2));
//excelContents.put("testsCount", tmpMap);
return excelContents;
}catch (Exception e){
System.out.println("發生異常:" + e);
}
return null;
}
public static File getExcelFileObj(String fPath){
try{
File fExl = new File(fPath);
return fExl;
}catch (Exception e){
System.out.println(e);
}
return null;
}
}
|
BeforeClass的處理
(代碼未經優化,有些地方可能寫得不合理,請見諒!)
//所有測試案例變量
public Map<String, HashMap> allIdAuthTestCases;
//測試案例文件路徑--excel作為存儲
public String testCasePath = new TestDirUtils().getTestCasesDir() + "/IdAuthTestCases.xls";
@BeforeClass
public void beforeClass() {
try{
allIdAuthTestCases = ExcelUtil.excelToHashMapByFirstSheet(testCasePath, "身份證鑒權");
}catch(Exception e){
e.printStackTrace();
}
}
@Test測試方法的處理
IdAuth.java類代碼
(代碼未經優化,有些地方可能寫得不合理,請見諒!)
package com.test.api;
import static org.testng.Assert.assertFalse;
import java.util.HashMap;
import java.util.Map;
import org.testng.Assert;
import org.testng.annotations.Test;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.AfterClass;
import com.test.pub.*;
public class IdAuth {
//所有測試案例變量
public Map<String, HashMap> allIdAuthTestCases;
//測試案例文件路徑--excel作為存儲
public String testCasePath = new TestDirUtils().getTestCasesDir() + "/IdAuthTestCases.xls";
@BeforeClass
public void beforeClass() {
try{
allIdAuthTestCases = ExcelUtils.excelToHashMapByFirstSheet(testCasePath, "身份證鑒權");
}catch(Exception e){
e.printStackTrace();
}
System.out.println("allIdAuthTestCases:" + allIdAuthTestCases);
}
/*
* ***************************** 身份證鑒權 *******************************
*/
/*
* 姓名為空
*/
@Test(timeOut=10000, description="姓名為空")
public void testById_NameIsNull() {
//測試案例編號
String testCaseCode = "ById_NameIsNull";
//測試數據
HashMap<String, String> testCaseData = new HashMap();
System.out.println("allIdAuthTestCases——>" + allIdAuthTestCases);
System.out.println(allIdAuthTestCases.containsKey(testCaseCode));
//判斷是否存在當前案例數據
try {
if (allIdAuthTestCases.containsKey(testCaseCode)) {
testCaseData = allIdAuthTestCases.get(testCaseCode);
//執行測試案例
//斷言測試結果
Assert.assertTrue(true);
} else {
Assert.fail("不存在當前測試方法的案例,請檢查測試案例文件!");
}
} catch(Exception e) {
e.printStackTrace();
Assert.fail("測試案例獲取失敗");
}
}
/*
* 證件號為空
*/
@Test(timeOut=10000, description="證件號為空")
public void testById_IdNoIsNull() {
//測試案例編號
String testCaseCode = "ById_IdNoIsNull";
//測試數據
HashMap<String, String> testCaseData = new HashMap();
//判斷是否存在當前案例數據
try {
if (allIdAuthTestCases.containsKey(testCaseCode)) {
testCaseData = allIdAuthTestCases.get(testCaseCode);
//執行測試案例
//斷言測試結果
Assert.assertTrue(false);
} else {
Assert.fail("不存在當前測試方法的案例,請檢查測試案例文件!");
}
} catch(Exception e) {
e.printStackTrace();
Assert.fail("測試案例獲取失敗");
}
}
/*
* 姓名與證件號均正確
*/
@Test(timeOut=10000, description="姓名與證件號均正確")
public void testById_IdNoAndNameRight() {
//測試案例編號
String testCaseCode = "ById_IdNoAndNameRight";
//測試數據
HashMap<String, String> testCaseData = new HashMap();
//判斷是否存在當前案例數據
try {
if (allIdAuthTestCases.containsKey(testCaseCode)) {
testCaseData = allIdAuthTestCases.get(testCaseCode);
//執行測試案例
//斷言測試結果
Assert.assertTrue(true);
} else {
Assert.fail("不存在當前測試方法的案例,請檢查測試案例文件!");
}
} catch(Exception e) {
e.printStackTrace();
Assert.fail("測試案例獲取失敗");
}
}
@AfterClass
public void afterClass() {
}
}
包com.test.pub下的TestDirUtils類代碼
(代碼未經優化,有些地方可能寫得不合理,請見諒!)
package com.test.pub;
public class TestDirUtils {
// 獲取主目錄
public String getMainDir() {
String userDir = System.getProperty("user.dir");
if (userDir.indexOf("target")>0) {
userDir = userDir.split("target")[0];
}
int userDirLen = userDir.length();
String subUserDir = userDir.substring(userDirLen-1, userDirLen);
if (subUserDir.equals("/")) {
userDir = userDir.substring(0, userDirLen-1);
}
return userDir;
}
// 獲取用例目錄路徑
public String getTestCasesDir() {
String testCasesDir = getMainDir();
if (testCasesDir.indexOf("target")>0) {
testCasesDir = testCasesDir.split("target")[0];
}
int userDirLen = testCasesDir.length();
String subUserDir = testCasesDir.substring(userDirLen-1, userDirLen);
if (subUserDir.equals("/")) {
testCasesDir = testCasesDir.substring(0, userDirLen-1);
}
return testCasesDir + "/src/test/resources/testcases";
}
}
運行結果:
OK, 大功告成,基本實現一個簡單的Maven+TestNG自動化測試框架。