freemarker的测试结果框架_TestNG框架Listener介绍及测试结果的收集
此文已由作者范旭斐授權(quán)網(wǎng)易云社區(qū)發(fā)布。
歡迎訪(fǎng)問(wèn)網(wǎng)易云社區(qū),了解更多網(wǎng)易技術(shù)產(chǎn)品運(yùn)營(yíng)經(jīng)驗(yàn)。
拋磚引玉
假設(shè)我們將testng作為自動(dòng)化測(cè)試框架的選型方案,以下兩個(gè)問(wèn)題如何實(shí)現(xiàn):
問(wèn)題1:如何將每次執(zhí)行(手動(dòng)或CI自動(dòng)構(gòu)建)后的每一條TestNG的測(cè)試結(jié)果,包括用例的描述,分組,優(yōu)先級(jí),執(zhí)行日志,執(zhí)行結(jié)果等存儲(chǔ)到數(shù)據(jù)庫(kù)存檔?
問(wèn)題2:在UI自動(dòng)化測(cè)試中,如何實(shí)現(xiàn)用例失敗自動(dòng)截屏功能?
TestNG的Listener列表
TestNG提供了一組預(yù)定義的Listener Java接口,這些接口全部繼承自TestNG的 ITestNGListener接口。用戶(hù)創(chuàng)建這些接口的實(shí)現(xiàn)類(lèi),并把它們加入到 TestNG 中,TestNG便會(huì)在測(cè)試運(yùn)行的不同時(shí)刻調(diào)用這些類(lèi)中的接口方法:
- IExecutionListener 監(jiān)聽(tīng)TestNG運(yùn)行的啟動(dòng)和停止。
- IAnnotationTransformer 注解轉(zhuǎn)換器,用于TestNG測(cè)試類(lèi)中的注解。
- ISuiteListener 測(cè)試套件監(jiān)聽(tīng)器,監(jiān)聽(tīng)測(cè)試套件的啟動(dòng)和停止。
- ITestListener 測(cè)試運(yùn)行的監(jiān)聽(tīng)器。
- IConfigurationListener 監(jiān)聽(tīng)配置方法相關(guān)的接口。
- IMethodInterceptor 用于修改TestNG即將運(yùn)行的測(cè)試方法列表。
- IInvokedMethodListener 測(cè)試方法攔截監(jiān)聽(tīng),用于獲取被TestNG調(diào)用的在Method的Before 和After方法監(jiān)聽(tīng)器。該方法只會(huì)被配置和測(cè)試方法調(diào)用。
- IHookable 若測(cè)試類(lèi)實(shí)現(xiàn)了該接口,當(dāng)@Test方法被發(fā)現(xiàn)時(shí),它的run()方法將會(huì)被調(diào)用來(lái)替代@Test方法。這個(gè)測(cè)試方法通常在IHookCallBack的callback之上調(diào)用,比較適用于需要JASS授權(quán)的測(cè)試類(lèi)。
- IReporter 實(shí)現(xiàn)該接口可以生成一份測(cè)試報(bào)告。
本文將著重介紹最常用到的兩個(gè)Listener ITestListener與Ireporter接口。ITestListener
實(shí)現(xiàn)ITestListener接口的類(lèi)在加入TestNG后,會(huì)在用例執(zhí)行期間,測(cè)試類(lèi)加載后,每個(gè)測(cè)試方法@Test之前前后調(diào)用執(zhí)行。以下為實(shí)現(xiàn)了該接口的一個(gè)demo類(lèi):
import org.testng.ITestContext; import org.testng.ITestListener; import org.testng.ITestResult; import org.testng.Reporter;public class KaolaTestListener implements ITestListener {//用例執(zhí)行結(jié)束后,用例執(zhí)行成功時(shí)調(diào)用public void onTestSuccess(ITestResult tr) {logTestEnd(tr, "Success");}//用例執(zhí)行結(jié)束后,用例執(zhí)行失敗時(shí)調(diào)用public void onTestFailure(ITestResult tr) {logTestEnd(tr, "Failed");}//用例執(zhí)行結(jié)束后,用例執(zhí)行skip時(shí)調(diào)用public void onTestSkipped(ITestResult tr) {logTestEnd(tr, "Skipped");}//每次方法失敗但是已經(jīng)使用successPercentage進(jìn)行注釋時(shí)調(diào)用,并且此失敗仍保留在請(qǐng)求的成功百分比之內(nèi)。public void onTestFailedButWithinSuccessPercentage(ITestResult tr) {logTestEnd(tr, "FailedButWithinSuccessPercentage");}//每次調(diào)用測(cè)試@Test之前調(diào)用public void onTestStart(ITestResult result) {logTestStart(result);}//在測(cè)試類(lèi)被實(shí)例化之后調(diào)用,并在調(diào)用任何配置方法之前調(diào)用。public void onStart(ITestContext context) {return;}//在所有測(cè)試運(yùn)行之后調(diào)用,并且所有的配置方法都被調(diào)用public void onFinish(ITestContext context) {return;}// 在用例執(zhí)行結(jié)束時(shí),打印用例的執(zhí)行結(jié)果信息protected void logTestEnd(ITestResult tr, String result) {Reporter.log(String.format("=============Result: %s=============", result), true);}// 在用例開(kāi)始時(shí),打印用例的一些信息,比如@Test對(duì)應(yīng)的方法名,用例的描述等等protected void logTestStart(ITestResult tr) {Reporter.log(String.format("=============Run: %s===============", tr.getMethod()), true);Reporter.log(String.format("用例描述: %s, 優(yōu)先級(jí): %s", tr.getMethod().getDescription(), tr.getMethod().getPriority()),true);return;} }這里寫(xiě)一個(gè)簡(jiǎn)單的demo用例:
@Test(description = "demo用例的示例描述", priority = 0)public void demo() throws IOException, InterruptedException {Reporter.log("步驟1:調(diào)用接口", true);HttpGetAPI getAPI = new HttpGetAPI();getAPI.setHost("127.0.0.1");getAPI.setPort("9999");getAPI.setPath("/api/sayHello");getAPI.getUriParams().put("name", "luck");getAPI.sendRequest(null);Reporter.log("步驟2:接口調(diào)用結(jié)果校驗(yàn)", true);getAPI.verifyResponseStatus(200, "");}將示例的 KaolaTestListener類(lèi)加入到 TestNG 中,運(yùn)行一個(gè)demo用例后的執(zhí)行效果如下:
可以看到用例運(yùn)行后的日志中,在用例開(kāi)始前與結(jié)束后添加了我們寫(xiě)的借助 org.testng.Reporter打印的一些日志信息。
IReporter
實(shí)現(xiàn)IReporter接口加入TestNG后,在每次測(cè)試執(zhí)行完后被調(diào)用執(zhí)行,可以獲取所有執(zhí)行的test suite,testcase的一些信息,可以用以生成一份測(cè)試報(bào)告。以下基于 extentreports實(shí)現(xiàn)IReporter接口,自定義擴(kuò)展的測(cè)試報(bào)告為例:
extentreports是 aventstack公司開(kāi)發(fā)的一個(gè)報(bào)告工具,其提供了開(kāi)源版本,支持java及.net項(xiàng)目的測(cè)試報(bào)告生成。extentreports的一些介紹:http://extentreports.com/docs/versions/3/java/
extentreports的pom依賴(lài):
<dependency><groupId>com.aventstack</groupId><artifactId>extentreports</artifactId><version>3.1.5</version></dependency><!-- https://mvnrepository.com/artifact/aopalliance/aopalliance --><dependency><groupId>aopalliance</groupId><artifactId>aopalliance</artifactId><version>1.0</version></dependency><!-- https://mvnrepository.com/artifact/aspectj/aspectjweaver --><dependency><groupId>aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.5.4</version></dependency>基于extentreports實(shí)現(xiàn)的IReporter接口:
import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.Map;import org.testng.IReporter; import org.testng.IResultMap; import org.testng.ISuite; import org.testng.ISuiteResult; import org.testng.ITestContext; import org.testng.ITestResult; import org.testng.Reporter; import org.testng.xml.XmlSuite;import com.netease.kaola.onlinetest.test.common.ExtentReportsContext; import com.alibaba.fastjson.JSONObject; import com.aventstack.extentreports.ExtentTest; import com.aventstack.extentreports.Status; import org.apache.commons.lang3.StringUtils;public class ExtentTestNGReporter implements IReporter {List groups = new ArrayList();public void generateReport(List xmlSuites, List suites, String outputDirectory) {for (ISuite suite : suites) {Map result = suite.getResults();for (ISuiteResult r : result.values()) {ITestContext context = r.getTestContext();ExtentTest parent = ExtentReportsContext.getInstance().createTest(context.getSuite().getName());ExtentReportsContext.parentTest.set(parent);buildTestNodes(context.getFailedTests(), Status.FAIL);buildTestNodes(context.getSkippedTests(), Status.SKIP);buildTestNodes(context.getPassedTests(), Status.PASS);for (String group : groups) {ExtentReportsContext.parentTest.get().assignCategory(group);ExtentReportsContext.getInstance().flush();}groups.clear();}}for (String s : org.testng.Reporter.getOutput()) {ExtentReportsContext.getInstance().setTestRunnerOutput(s);}}private void buildTestNodes(IResultMap tests, Status status) {if (tests.size() > 0) {for (ITestResult result : tests.getAllResults()) {ExtentTest child = ExtentReportsContext.parentTest.get().createNode(result.getMethod().getMethodName());ExtentReportsContext.test.set(child);String groupsStr = "";for (String group : result.getMethod().getGroups()) {if (!groups.contains(group)) {groups.add(group);}if (!StringUtils.isEmpty(groupsStr)) {groupsStr += "|";}groupsStr += group;ExtentReportsContext.test.get().assignCategory(group);}if (!StringUtils.isEmpty(result.getMethod().getDescription())) {ExtentReportsContext.test.get().log(Status.PASS,String.format("用例描述:%s Priority:%s 分組:%s", result.getMethod().getDescription(),Integer.toString(result.getMethod().getPriority()), groupsStr));}if (result.getParameters().length > 0) {for (int i = 0; i < result.getParameters().length; i++) {ExtentReportsContext.test.get().log(Status.PASS, "用例參數(shù)列表:");ExtentReportsContext.test.get().log(Status.PASS, String.format("第%d個(gè)參數(shù):", i + 1));ExtentReportsContext.test.get().log(Status.PASS,JSONObject.toJSONString(result.getParameters()[i]));}}ExtentReportsContext.test.get().log(Status.PASS,String.format("=============Run: %s===============", result.getMethod()));List outputs = Reporter.getOutput(result);if (outputs != null) {for (String output : outputs) {ExtentReportsContext.test.get().log(Status.PASS, output);}}if (result.getThrowable() != null) {ExtentReportsContext.test.get().log(status, result.getThrowable());}ExtentReportsContext.test.get().getModel().setStartTime(getTime(result.getStartMillis()));ExtentReportsContext.test.get().getModel().setEndTime(getTime(result.getEndMillis()));}ExtentReportsContext.getInstance().flush();}}private Date getTime(long millis) {Calendar calendar = Calendar.getInstance();calendar.setTimeInMillis(millis);return calendar.getTime();} }import com.aventstack.extentreports.ExtentReports; import com.aventstack.extentreports.ExtentTest; import com.aventstack.extentreports.ResourceCDN; import com.aventstack.extentreports.reporter.ExtentHtmlReporter; import com.aventstack.extentreports.reporter.configuration.ChartLocation;public class ExtentReportsContext {private static ExtentReports extent;public static ThreadLocal parentTest = new ThreadLocal();public static ThreadLocal test = new ThreadLocal();public static ExtentReports getInstance() {if (extent == null)createInstance("接口測(cè)試報(bào)告.html");return extent;}public static ExtentReports createInstance(String fileName) {ExtentHtmlReporter htmlReporter = new ExtentHtmlReporter(fileName);htmlReporter.config().setTestViewChartLocation(ChartLocation.BOTTOM);htmlReporter.config().setChartVisibilityOnOpen(true);// htmlReporter.config().setTheme(Theme.STANDARD);htmlReporter.config().setResourceCDN(ResourceCDN.EXTENTREPORTS);htmlReporter.config().setDocumentTitle(fileName);htmlReporter.config().setEncoding("utf-8");htmlReporter.config().setReportName(fileName);extent = new ExtentReports();extent.attachReporter(htmlReporter);return extent;} }這里 ExtentReportsContext與 ExtentTestNGReporter的編寫(xiě)主要參考extentreports的官方文檔:http://extentreports.com/docs/versions/3/java/#testng-ireporter
將示例的ExtentTestNGReporter類(lèi)加入到 TestNG 中,運(yùn)行一個(gè)demo用例后,可以在target目錄下查看生成的接口測(cè)試報(bào)告 “接口測(cè)試報(bào)告.html”:
可以看到extentreports比原生的testng生成的測(cè)試報(bào)告界面更友好,內(nèi)容也更豐富。因?yàn)槲覀冊(cè)贓xtentTestNGReporter用到了org.testng.Reporter. getOutput(ITestResult tr )方法,所以所有調(diào)用到org.testng.Reporter. log()方法的地方,都可以在測(cè)試報(bào)告中展示出來(lái)。
如何將實(shí)現(xiàn)了ITestNGListener接口加入到TestNG中
這里有三個(gè)地方可以為T(mén)estNG配置Listener
- pom文件中maven-surefire-plugin插件,maven-surefire-plugin插件集成了TestNG&JUnit,任何實(shí)現(xiàn)了ITestNGListener的接口的類(lèi)都可以配置進(jìn)來(lái)。
testng的xml配置文件中
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="dubbok_bvt_testsuite" verbose="1" parallel="false"><test name="dubbok_bvt_testsuite"><groups><run><include name="dubbok" /></run></groups><packages><package name="com.netease.kaola.onlinetest.test.bvt.dubbok.*" /></packages></test><listeners><listener class-name="com.netease.kaola.onlinetest.test.common.ExtentTestNGReporter" /><listener class-name="com.netease.kaola.onlinetest.test.common.KaolaTestListener" /></listeners> </suite>測(cè)試類(lèi)添加注解標(biāo)簽
package com.netease.kaola.onlinetest.test.base;import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.testng.AbstractTestNGSpringContextTests; import org.testng.annotations.Listeners;import com.netease.kaola.onlinetest.test.common.KaolaTestListener;@Listeners({ KaolaTestListener.class }) @ContextConfiguration(locations = { "classpath:application.xml" }) public abstract class BaseTest extends AbstractTestNGSpringContextTests { }回到開(kāi)始的問(wèn)題
假設(shè)我們將testng作為自動(dòng)化測(cè)試框架的選型方案,以下兩個(gè)問(wèn)題如何實(shí)現(xiàn):
問(wèn)題1:如何將每次執(zhí)行(手動(dòng)或CI自動(dòng)構(gòu)建)后的每一條TestNG的測(cè)試結(jié)果,包括用例的描述,分組,優(yōu)先級(jí),執(zhí)行日志,執(zhí)行結(jié)果等存儲(chǔ)到數(shù)據(jù)庫(kù)存檔?
答案:實(shí)現(xiàn)一個(gè)TestNG的IReporter接口,在自定義的Reporter類(lèi)中,將需要的一些用例信息收集出來(lái),保存在數(shù)據(jù)庫(kù)中,最后將自定義的Reporter類(lèi)配置在TestNG中。
問(wèn)題2:在UI自動(dòng)化測(cè)試中,如何實(shí)現(xiàn)用例失敗自動(dòng)截屏功能?
答案:實(shí)現(xiàn)一個(gè)TestNG的 ITestListener 接口,在自定義的TestListener類(lèi)的 onTestFailure()方法中實(shí)現(xiàn)截屏邏輯 ,最后將自定義的 TestListener 類(lèi)配置在TestNG中。
免費(fèi)領(lǐng)取驗(yàn)證碼、內(nèi)容安全、短信發(fā)送、直播點(diǎn)播體驗(yàn)包及云服務(wù)器等套餐
更多網(wǎng)易技術(shù)、產(chǎn)品、運(yùn)營(yíng)經(jīng)驗(yàn)分享請(qǐng)點(diǎn)擊。
總結(jié)
以上是生活随笔為你收集整理的freemarker的测试结果框架_TestNG框架Listener介绍及测试结果的收集的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 游戏中的数学与物理学 第二版_在游戏中启
- 下一篇: python for循环结构_循环结构-