如何基于TestNg的特性提升自動化穩(wěn)定性

前言

接口自動化測試棚饵,是所有測試人員必備的一項技能骗灶,建立一套穩(wěn)定混驰、可用率高的測試用例集,能夠幫助測試人員提升測試效率闲昭,是日常工作中不可或缺的小技能。本文主要基于業(yè)界使用廣泛的TestNG框架進行展開靡挥,介紹TestNG在實際工程實踐中的應用序矩。
眾所周知,TestNG之所以能夠作為一款優(yōu)秀的測試框架被廣泛應用跋破,主要在于其具備Annotation簸淀、依賴性測試、支持并發(fā)測試毒返、支持錯誤重試啃擦、用例管理、以及測試報告的自定義等特性饿悬,能夠幫助測試人員對測試用例進行高效的管理和維護令蛉,看看如何基于TestNG框架解決測試過程中的一些痛點。

痛點

  1. 自動化case多,用例執(zhí)行順序混亂珠叔。
    在測試過程中蝎宇,常常會遇到場景A依賴于場景B的情況,舉個栗子:
    當我創(chuàng)建了一個typeA的廣告祷安,針對廣告A我需要創(chuàng)建一些創(chuàng)意姥芥,關于typeA廣告的case執(zhí)行完成后,需要刪除typeA廣告汇鞭。再創(chuàng)建typeB的廣告凉唐,再執(zhí)行typeB廣告的case。但是在使用testng過程中發(fā)現(xiàn)霍骄,在同一個測試類中台囱,@test默認測試方法的執(zhí)行順序是按照方法名的首字母升序排序執(zhí)行的,這就會導致在執(zhí)行typeA廣告相關case執(zhí)行了一半后读整,又去執(zhí)行typeB廣告相關的case簿训。而我們針對case執(zhí)行的前置條件,是以group維度進行配置的米间,那么就會出現(xiàn)在執(zhí)行typeA相關的case時强品,typeA的廣告已經(jīng)被刪除了。
  2. 自動化不穩(wěn)定
    在自動化用例的實際應用時屈糊,經(jīng)常會出現(xiàn)的榛,單獨跑一個case的時候,是成功的逻锐,而跑全量case時夫晌,經(jīng)常會出現(xiàn)部分case失敗的情況。
  3. 異步接口多谦去,等待耗時過長
    在一些高并發(fā)場景中慷丽,服務器需要處理的事務較多蹦哼,很多接口采用的是異步調(diào)用的方式鳄哭,等待時間不確定,常常導致接口的返回結(jié)果和預期不符纲熏,斷言失敗妆丘。
    那么接下來主要針對以上幾點,介紹一下以上問題的解決方案局劲。

痛點解決方案及優(yōu)化

  1. 自動化case多勺拣,用例執(zhí)行順序混亂
    針對這種現(xiàn)象,TestNg其實提供了很好的解決方案:
  • Method1.
    在testclass維度鱼填,可以通過testng.xml來進行管理
  <test name="創(chuàng)建feeds卡片" preserve-order="true">
         <classes>
             <class name="bce.feed.IFeedCardType1"/>
             <class name="bce.feed.IFeedCardType2"/>
             <class name="bce.feed.IFeedCardType3"/>
             <class name="bce.feed.IFeedCardType7"/>
         </classes>
    </test>

如上药有,通過presever-order這個屬性,來控制case按順序執(zhí)行。

  • Method2.
    testclass中的每一個case的執(zhí)行順序是不受preserve-order控制的愤惰,而是按case首字母的順序來執(zhí)行苇经。這時就需要通過priority來指定執(zhí)行順序(默認值為0),數(shù)值越小宦言,越靠前執(zhí)行扇单。

step1.創(chuàng)建監(jiān)聽器

public class RePrioritizingListener implements IAnnotationTransformer {

    HashMap<Object, Integer> priorityMap = new HashMap<Object, Integer>();
    Integer class_priorityCounter = 10000;
    Integer max_testpriorityLength = 4;

    @Override
    public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) {

        Class<?> declaringClass = testMethod.getDeclaringClass();
        Integer test_priority = annotation.getPriority();
        Integer current_ClassPriority = priorityMap.get(declaringClass);
        //修改當前類中的@test的priority值
        if (current_ClassPriority == null) {
            current_ClassPriority = class_priorityCounter++;
            priorityMap.put(declaringClass, current_ClassPriority);
        }

        String concatenatedPriority = test_priority.toString();
        while (concatenatedPriority.length() < max_testpriorityLength) {
            concatenatedPriority = "0" + concatenatedPriority;
        }
        concatenatedPriority = current_ClassPriority.toString() + concatenatedPriority;

        annotation.setPriority(Integer.parseInt(concatenatedPriority));
    }

}

加這個監(jiān)聽的原因是:priority是在testng開始時候一次性加載進去的,不同類中priority相同的case會一起執(zhí)行奠旺,仍然會出現(xiàn)case亂序的情況蜘澜。所以需要 implement IAnnotationTransformer 對每個class 的method priority 進行重置。
step2. 在testNG的xml中添加監(jiān)聽

<listener class-name="base.RePrioritizingListener"/>

step3.在測試類中添加priority值(默認值為0响疚,數(shù)值越小鄙信,越靠前執(zhí)行),并設置dependsOnGroups稽寒。

public class TestClassA {

    @Test(priority=1,group = "1")
    public testMethod1 (){
    }
    @Test(priority=2,group = "1")
    public testMethod2 (){
    }
    @Test(priority=3,,group = "1")
    public testMethod3 (){
    }
}
public class TestClassB {
    @Test(priority=1,dependsOnGroups= {"1"})
    public void ttestMethod4() {
    }
    @Test(priority=2,dependsOnGroups= {"1"})
    public void testMethod5() {
    }
    @Test(priority=3,dependsOnGroups= {"1"})
    public void testMethod6() {
    }
}
  1. 自動化不穩(wěn)定
    自動化不穩(wěn)定的原因有很多扮碧,在case并發(fā)執(zhí)行的過程中,很可能由于環(huán)境的原因杏糙,會造成我們的用例失敗慎王。testNg的IRetryAnalyzer接口可以有效地幫助我們解決此類問題。具體實施步驟如下:
    step1.添加監(jiān)聽宏侍,實現(xiàn)IAnnotationTransformer赖淤,重寫transform方法。
public class RetryListener implements IAnnotationTransformer {

    @Override
    public void transform(ITestAnnotation iTestAnnotation, Class testClass, Constructor constructor, Method method) {

        IRetryAnalyzer iRetryAnalyzer= iTestAnnotation.getRetryAnalyzer();
        if(iRetryAnalyzer==null){
            iTestAnnotation.setRetryAnalyzer(CustomRetry.class);
        }
    }
}

這里做的工作就是掃描所有的@Test方法是否具有retryAnalyzer屬性谅河,沒有則為其設置重試屬性(即@Test(retryAnalyzer = CustomRetry.class))咱旱。而具體的重試機制,可以通過實現(xiàn)IRetryAnalyzer接口绷耍,進行自定義實現(xiàn)吐限。

step2.實現(xiàn)IRetryAnalyzer接口

public class CustomRetry implements IRetryAnalyzer {
    private static final Logger logger = LoggerFactory.getLogger(CustomRetry.class);
    private int initRetryCount = 0;
    private int maxRetryCount = 3; //失敗重跑次數(shù)

    @Override
    public boolean retry(ITestResult iTestResult) {
        if(initRetryCount < maxRetryCount){
            initRetryCount++;
            logger.debug("================ {}.{} 重試第{}次==============",iTestResult.getTestClass().getName(),iTestResult.getName(),initRetryCount);
            try {
                Thread.sleep(2000);
            }catch (InterruptedException e) {
                e.printStackTrace();
            }
            return true;
        }
        return false;
    }
}

這邊我設置了失敗重跑次數(shù)為3,如果重跑失敗褂始,則會被ignore诸典。

step3. 應用
1.全局生效
在testng.xml中配置監(jiān)聽

<listeners>
        <listener class-name="base.RetryListener"/>
</listeners>

2.單用例

@Test(groups = "filterCpm",retryAnalyzer = CustomRetry.class)
    public void test_non_blueVip_not_filtered_cpm(){
        boolean is_ad = blueVipBaseTest("123456");
        Assert.assertTrue(is_ad);
    }

效果如下圖,用例失敗后會重試三次


失敗重試三次
  1. 異步接口多崎苗,等待耗時過長
    解決此類問題的方法是輪詢狐粱。
    public void refreshRtbAdsData(Integer creativeId) throws InterruptedException{
        int count = 10;//輪詢限制重試次數(shù)
        HttpRequestUtil httpRequestUtil = new HttpRequestUtil();
        httpRequestUtil.addheader("Content-Type", "application/json");
        String refreshData = httpRequestUtil.getResponseBody(Config.rtbRefrshUrl,"get");
        while (!refreshData.contains(String.valueOf(creativeId)) && count > 0){
            httpRequestUtil.addheader("Content-Type", "application/json");
            refreshData = httpRequestUtil.getResponseBody(Config.rtbRefrshUrl,"get");
            count--;
            Thread.sleep(2000);//控制請求頻率
        }
    }

上面的方法就是輪詢10次,每2000ms輪詢一次胆数,直到拿到所需的創(chuàng)意肌蜻。通過這種方式,我們用例集執(zhí)行時間減少了一半必尼,同時穩(wěn)定性也得以提升蒋搜。

4.自定義測試報告
自定義測試報告主要是方便對測試結(jié)果進行整理,同時提升定位問題的效率。具體步驟如下:
step1. 創(chuàng)建監(jiān)聽重寫onFinish方法豆挽。主要目的是對測試的結(jié)果進行整理打包酸休,以郵件的方式發(fā)送給相關責任人。

public class TestngListener extends TestListenerAdapter {
    public void onFinish(ISuite iSuite) {
        ReportStaticFactory.copyReportStatic();
        ReplaceHtmlReportStaticLocation.replaceStatic();

        try {
            ZipUtil.doZip("test-output", "test-output/report.zip");
        } catch (IOException var11) {
            var11.printStackTrace();
        }

        String projectName = ISuiteInfo.getSuiteName(iSuite);
        ArrayList<HashMap<String, Integer>> suiteResult = ISuiteInfo.getSuiteResult(iSuite);
        Boolean suiteState = ISuiteInfo.getSuiteState(iSuite);
        String testResultState = suiteState ? "Pass" : "Fail";
        (new StringBuilder()).append(projectName).append(" - 測試結(jié)果 - ").append(testResultState).toString();
        String htmlMailContent = null;
        ArrayList failResults = ISuiteInfo.getFailResults(iSuite);

        try {
            HtmlMailContent.getHtmlMailContent(projectName, suiteState, suiteResult, failResults);
        } catch (TemplateException | IOException var10) {
            var10.printStackTrace();
        }
    }
}

step2.配置

<listeners>
  <listener class-name="base.TestngListener"/>
</listeners>

總結(jié)

以上就是基于TestNG的一些自動化實踐的總結(jié)祷杈,后續(xù)如有更好的應用斑司,再做補充啦~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市但汞,隨后出現(xiàn)的幾起案子宿刮,更是在濱河造成了極大的恐慌,老刑警劉巖私蕾,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件僵缺,死亡現(xiàn)場離奇詭異,居然都是意外死亡踩叭,警方通過查閱死者的電腦和手機磕潮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來容贝,“玉大人自脯,你說我怎么就攤上這事〗锔唬” “怎么了膏潮?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長满力。 經(jīng)常有香客問我焕参,道長,這世上最難降的妖魔是什么油额? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任叠纷,我火速辦了婚禮,結(jié)果婚禮上潦嘶,老公的妹妹穿的比我還像新娘涩嚣。我一直安慰自己,他們只是感情好衬以,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布缓艳。 她就那樣靜靜地躺著校摩,像睡著了一般看峻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上衙吩,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天互妓,我揣著相機與錄音,去河邊找鬼。 笑死冯勉,一個胖子當著我的面吹牛澈蚌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播灼狰,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼宛瞄,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了交胚?” 一聲冷哼從身側(cè)響起份汗,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蝴簇,沒想到半個月后杯活,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡熬词,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年旁钧,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片互拾。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡歪今,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出颜矿,到底是詐尸還是另有隱情彤委,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布或衡,位于F島的核電站焦影,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏封断。R本人自食惡果不足惜斯辰,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望坡疼。 院中可真熱鬧彬呻,春花似錦、人聲如沸柄瑰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽教沾。三九已至蒲跨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間授翻,已是汗流浹背或悲。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工孙咪, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人巡语。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓翎蹈,卻偏偏與公主長得像,于是被迫代替她去往敵國和親男公。 傳聞我的和親對象是個殘疾皇子荤堪,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344