TESTNG使用

TestNG

TestNG是一個測試Java應用程序的開源框架,類似JUnit和NUnit。

環境配置

  • 配置好java環境,命令行java -version查看
  • 官網 , 下載對應系統下jar文件
  • 系統環境變量中添加指向jar文件所在路徑
  • Eclipse中安裝testng,Help -> Install New Software,Add http://beust.com/eclipse

TestNG 基本用法


import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.testng.annotations.Test;

public class TestNGLearn1 {

    @BeforeClass
    public void beforeClass() {
        System.out.println("this is before class");
    }

    @Test
    public void TestNgLearn() {
        System.out.println("this is TestNG test case");
    }

    @AfterClass
    public void afterClass() {
        System.out.println("this is after class");
    }
}

TestNG 基本註解

註解 描述
@BeforeSuite 註解的方法將只運行一次,運行所有測試前此套件中
@AfterSuite 註解的方法將只運行一次此套件中的所有測試都運行之後
@BeforeClass 註解的方法將只運行一次先行先試在當前類中的方法調用
@AfterClass 註解的方法將只運行一次後已經運行在當前類中的所有測試方法
@BeforeTest 註解的方法將被運行之前的任何測試方法屬於內部類的 <test>標籤的運行
@AfterTest 註解的方法將被運行後,所有的測試方法,屬於內部類的<test>標籤的運行
@BeforeGroups 組的列表,這種配置方法將之前運行。此方法是保證在運行屬於任何這些組第一個測試方法,該方法被調用
@AfterGroups 組的名單,這種配置方法後,將運行。此方法是保證運行後不久,最後的測試方法,該方法屬於任何這些組被調用
@BeforeMethod 註解的方法將每個測試方法之前運行
@AfterMethod 被註釋的方法將被運行後,每個測試方法
@DataProvider 標誌着一個方法,提供數據的一個測試方法。註解的方法必須返回一個Object[] [],其中每個對象[]的測試方法的參數列表中可以分配。該@Test 方法,希望從這個DataProvider的接收數據,需要使用一個dataProvider名稱等於這個註解的名字
@Factory 作爲一個工廠,返回TestNG的測試類的對象將被用於標記的方法。該方法必須返回Object[]
@Listeners 定義一個測試類的監聽器
@Parameters 將xml文件中參數傳遞給@Test方法
@Test 標記一個類或方法作爲測試的一部分

testng.xml

屬性 描述
name suite的名字(他會出現在測試報告中)
junit 是否以junit模式運行
verbose 在控制檯中如何輸出,這個設置不影響html版本的測試報告
parallel 是否使用多線程測試(可加速測試)
configfailurepolicy 是否在運行失敗了一次後繼續嘗試或跳過
thread-count 如果設置了parallel,可以設置線程數
annotations 有‘javadoc’的時候尋找,沒有的話使用jdk5的註釋
time-out 在終止method (如果parallel="methods") 或者test (如果parallel="tests")之前設置以毫秒爲單位的等待時間
skipfailedinvocationcounts 是否跳過失敗的調用
data-provider-thread-count 提供一個整數線程池的範圍爲了使用parallel data
object-factory 一個繼承IObjectFactory的類,被用來實例化測試對象
allow-return-values 如果設置true,將會運行測試用例並返回值

示例


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Suite" parallel="tests" thread-count="5">
    <test name="Test" preserve-order="true" verbose="2">
        <parameter name="userName" value="15952031403"></parameter>
        <parameter name="originPwd" value="c12345"></parameter>
        <classes>
            <class name="com.unionpay.testng.UPPayRegisterTest">
            </class>
        </classes>
    </test>
    <!-- <test name="Test1" preserve-order="true">
        <classes>
        <class name="com.unionpay.testng.Test2">
            </class>
        </classes>
    </test>
    <test name="Test2" preserve-order="true">
        <classes>
        <class name="com.unionpay.testng.Test3">
            </class>
        </classes>
    </test> -->
</suite> <!-- Suite -->
  • parallelthread-count分別指定並行化測試的範圍(tests, methodsclasses)和並行線程數
  • preserve-order,設爲true時,節點下的方法按順序執行
  • verbose 表示記錄的日誌級別,在0-10之間取值
  • <parameter name="userName", value="1595203xxxx"/> 給測試代碼傳遞參數鍵值對,在測試類中通過註解@Parameters({"userName","originPwd"})獲取

參數化測試

當測試邏輯一樣,只是參數不一樣時,採用數據驅動測試機制,避免寫重複代碼。TestNG中通過@DataProvider實現數據驅動。

利用@DataProvider做數據驅動,數據源文件可以是EXCEL,XML,甚至可以是TXT文本。以讀取xml文件爲例,通過@DataProvider讀取XML文件中數據,然後測試方法只要標示獲取數據來源的DataProvider,那麼對應的DataProvider會把讀取的數據傳給該test方法。

 

DataProvider原理

1. 構建xml數據文件

<?xml version="1.0" encoding="UTF-8"?>
<data>
    <login>
        <username>user1</username>
        <password>123456</password>
    </login>
    <login>
        <username>user2</username>
        <password>345678</password>
    </login>
</data>

2. 讀取xml文件


import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

public class ParseXml {

    /**
     * 利用Dom4j解析xml文件,返回list
     * @param xmlFileName
     * @return
     */
    public static List parse3Xml(String xmlFileName){
    File inputXml = new File(xmlFileName);    
        List list= new ArrayList();                
        int count = 1;
        SAXReader saxReader = new SAXReader();
        try {
            Document document = saxReader.read(inputXml);
            Element items = document.getRootElement();
            for (Iterator i = items.elementIterator(); i.hasNext();) {
                Element item = (Element) i.next();
                Map map = new HashMap();
                Map tempMap = new HashMap();
                for (Iterator j = item.elementIterator(); j.hasNext();) {
                    Element node = (Element) j.next();                    
                    tempMap.put(node.getName(), node.getText());                    
                }
                map.put(item.getName(), tempMap);
                list.add(map);
            }
        } catch (DocumentException e) {
            System.out.println(e.getMessage());
        }
        System.out.println(list.size());
        return list;
    }    
}

3. DataProvider類


import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.testng.Assert;
import org.testng.annotations.DataProvider;

public class GenerateData {
    
    public static List list = new ArrayList();
    
    @DataProvider(name = "dataProvider")
    public static Object[][] dataProvider(Method method){      
    list = ParseXml.parse3Xml("absolute path of  xml file");
        List<Map<String, String>> result = new ArrayList<Map<String, String>>();        
        for (int i = 0; i < list.size(); i++) {
            Map m = (Map) list.get(i);    
            if(m.containsKey(method.getName())){                            
                Map<String, String> dm = (Map<String, String>) m.get(method.getName());
                result.add(dm);    
            }
        }  
        if(result.size() > 0){
            Object[][] files = new Object[result.size()][];
            for(int i=0; i<result.size(); i++){
                files[i] = new Object[]{result.get(i)};
            }        
            return files;
        }else {
            Assert.assertTrue(result.size()!=0,list+" is null, can not find"+method.getName() );
        return null;
    }
    }

}

4. 在test方法中引用dataprovider


public class LoginTest {
 @Test(dataProvider="dataProvider", dataProviderClass= GenerateData.class)
    public  void login(Map<String, String> param) throws InterruptedException{

        List<WebElement> edits = findElementsByClassName(AndroidClassName.EDITTEXT);
        edits.get(0).sendkeys(param.get("username"));
        edits.get(1).sendkeys(param.get("password"));
    }
}

xml中的父節點與test方法名對應,因此xml中同名父節點的個數就意味着該test方法會被重複執行多少次; 當dataprovider與test方法不在同一個類時,需指明dataprovider類,如dataProviderClass= GenerateData.class

TestNG重寫監聽類

TestNG會監聽每個測試case的運行結果,有時候我們需要定製一些其他功能,如自動截圖,發送數據給服務器等。方法是新建一個繼承TestListenerAdapter的類。
重寫完成後,在需要的test方法前添加註解@Listeners(TestNGListener.class)


package com.unionpay.listener;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.testng.ITestContext;
import org.testng.ITestResult;
import org.testng.TestListenerAdapter;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.unionpay.base.BaseTest;
import com.unionpay.constants.CapabilitiesBean;
import com.unionpay.constants.CaseCountBean;
import com.unionpay.constants.ResultBean;
import com.unionpay.util.Assertion;
import com.unionpay.util.PostService;
import com.unionpay.util.ReadCapabilitiesUtil;

/**
 * 帶有post請求的testng監聽
 * @author lichen2
 */
public class TestNGListenerWithPost extends TestListenerAdapter{
    
    //接收每個case結果的接口
    private String caseUrl;
    
    //接收整個test運行數據的接口
    private String countUrl;
    
    //接收test運行狀態的接口
    private String statusUrl;
    
    private JsonObject caseResultJson = new JsonObject();
    
    private JsonObject caseCountJson = new JsonObject();
    
    private Gson gson = new Gson();
    
    private ResultBean result = new ResultBean();
    
    private CaseCountBean caseCount = new CaseCountBean();
    
    private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    
    private CapabilitiesBean capabilitiesBean = ReadCapabilitiesUtil.readCapabilities("setting.json");
    
    private String testStartTime;
    
    private String testEndTime;
    
    private String runId;
    
    //testng初始化
    @Override
    public void onStart(ITestContext testContext) {
        super.onStart(testContext);
        String serverUrl = capabilitiesBean.getServerurl();
    caseUrl = "http://"+serverUrl+"/api/testcaseResult";
    countUrl = "http://"+serverUrl+"/api/testcaseCount";
    statusUrl = "http://"+serverUrl+"/api/testStatus";
        runId = capabilitiesBean.getRunid();
        result.setRunId(runId);
        caseCount.setRunId(runId);
    }
    
    //case開始
    @Override
    public void onTestStart(ITestResult tr) {
    Assertion.flag = true;
    Assertion.errors.clear();
    sendStatus("運行中");
    result.setStartTime(format.format(new Date()));
    }
    
    //case成功執行
    @Override
    public void onTestSuccess(ITestResult tr) {
        super.onTestSuccess(tr);
        sendResult(tr);
        takeScreenShot(tr);
    }

    //case執行失敗
    @Override
    public void onTestFailure(ITestResult tr) {
        super.onTestFailure(tr);
        sendResult(tr);
        try {
            takeScreenShot(tr);
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {         
            e.printStackTrace();
        }
        this.handleAssertion(tr);
    }

    //case被跳過
    @Override
    public void onTestSkipped(ITestResult tr) {
        super.onTestSkipped(tr);
        takeScreenShot(tr);
        sendResult(tr);
        this.handleAssertion(tr);
    }

    //所有case執行完成
    @Override
    public void onFinish(ITestContext testContext) {
        super.onFinish(testContext);
        sendStatus("正在生成報告");
        sendFinishData(testContext);
    }
    
    /**
     * 發送case測試結果
     * @param tr
     */
    public void sendResult(ITestResult tr){
    result.setTestcaseName(tr.getName());
    result.setEndTime(format.format(new Date()));
    float tmpDuration = (float)(tr.getEndMillis() - tr.getStartMillis());
    result.setDuration(tmpDuration / 1000);
    
    switch (tr.getStatus()) {
    case 1:
        result.setTestResult("SUCCESS");
        break;
    case 2:
        result.setTestResult("FAILURE");
        break;
    case 3:
        result.setTestResult("SKIP");
        break;
    case 4:
        result.setTestResult("SUCCESS_PERCENTAGE_FAILURE");
        break;
    case 16:
        result.setTestResult("STARTED");
        break;
    default:
        break;
    }
    caseResultJson.addProperty("result", gson.toJson(result));
    PostService.sendPost(caseUrl, caseResultJson.toString());
    }
    
    /**
     * 通知test完成
     * @param testContext
     */
    public void sendFinishData(ITestContext tc){
    testStartTime = format.format(tc.getStartDate());
    testEndTime = format.format(tc.getEndDate());
    long duration = getDurationByDate(tc.getStartDate(), tc.getEndDate());
    caseCount.setTestStartTime(testStartTime);
    caseCount.setTestEndTime(testEndTime);
    caseCount.setTestDuration(duration);
    caseCount.setTestSuccess(tc.getPassedTests().size());
    caseCount.setTestFail(tc.getFailedTests().size());
    caseCount.setTestSkip(tc.getSkippedTests().size());
    
    caseCountJson.addProperty("count", gson.toJson(caseCount));
    PostService.sendPost(countUrl, caseCountJson.toString());
    }
    
    /**
     * 通知test運行狀態
     */
    public void sendStatus(String status){
    JsonObject jsonObject = new JsonObject();
    jsonObject.addProperty("runId", runId);
    jsonObject.addProperty("status", status);
    JsonObject sendJson = new JsonObject();
    sendJson.addProperty("status", jsonObject.toString());
    PostService.sendPost(statusUrl, sendJson.toString());
    }
    
    //計算date間的時差(s)
    public long getDurationByDate(Date start, Date end){
    long duration = end.getTime() - start.getTime();
    return duration / 1000;
    }

    //截圖
    private void takeScreenShot(ITestResult tr) {
        BaseTest b = (BaseTest) tr.getInstance();
        b.takeScreenShot(tr);
    }
}

** BaseTest **


package com.unionpay.base;

import org.testng.ITestResult;
import com.unionpay.listener.TestNGListenerWithPost;
@Listeners(TestNGListenerWithPost.class)
public abstract class BaseTest {
    public AndroidDriver<WebElement> driver;
    public BaseTest() {
    driver = DriverFactory.getDriverByJson();
    }

    /**
     * 截屏並保存到本地
     * @param tr
     */
    public void takeScreenShot(ITestResult tr) {
    String fileName = tr.getName() + ".jpg";
    File dir = new File("target/snapshot");
    if (!dir.exists()) {
        dir.mkdirs();
    }
    String filePath = dir.getAbsolutePath() + "/" + fileName;
    if (driver != null) {
        try {
        File scrFile = driver.getScreenshotAs(OutputType.FILE);
        FileUtils.copyFile(scrFile, new File(filePath));
        } catch (IOException e) {
        e.printStackTrace();
        }
    }
    }
}


 

?mid=&wid=51824&sid=&tid=8731&rid=LOADED&custom1=mp.csdn.net&custom2=%2Fpostedit%2F79312321&t=1577418159376?mid=&wid=51824&sid=&tid=8731&rid=FINISHED&custom1=mp.csdn.net&t=1577418159376

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章