<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    qileilove

    blog已經(jīng)轉(zhuǎn)移至github,大家請(qǐng)?jiān)L問(wèn) http://qaseven.github.io/

    2013年度持續(xù)集成實(shí)踐小結(jié)[2] —單元測(cè)試

      前文提到,在UI自動(dòng)化之外,我們著力探索了如何實(shí)施單元測(cè)試(unit test
      相對(duì)于UI自動(dòng)化,單元測(cè)試方面的實(shí)踐還是不夠充分的,因此,這里也只是小結(jié)一下我們的經(jīng)驗(yàn)
      概述
      首先明確一下,此處單元測(cè)試概念與經(jīng)典意義有所不同,泛指所有:
      由開(kāi)發(fā)工程師編寫(xiě)的,可以在開(kāi)發(fā)本地一鍵運(yùn)行的,運(yùn)行時(shí)間在分鐘級(jí)別的測(cè)試用例,用例執(zhí)行會(huì)依賴不多的,但往往也是穩(wěn)定可靠的外部環(huán)境
      測(cè)試框架一般使用TestNg而不是JUnit,主要原因在于TestNg的 DataProvider 功能很給力,非常適合用例須要覆蓋多分支的場(chǎng)景
      用例組織原則:
      一個(gè)測(cè)試類對(duì)應(yīng)一個(gè)功能類: funcOneTest.java 對(duì)應(yīng)于 funcOne.java
      若干個(gè)測(cè)試方法對(duì)應(yīng)一個(gè)功能方法:test_funcOne_smoke() & test_funcOne_normal() & test_funcOne_error() 對(duì)應(yīng)于 funcOne()
      用例分類約定
      還是以 超市購(gòu)物 為背景,寫(xiě)幾個(gè)Demo用例
      Δ冒煙型用例 – 甲
    @Test(description = "getNewestItems_冒煙_獲取最新商品并檢查若干關(guān)鍵屬性")
    public void test_getNewestItems_smoke() {
    List<ItemVo> itemList = itemBean.getNewestItems(1);
    Assert.assertTrue(itemList.size() == 16,        "size應(yīng)該是16");
    for (ItemVo vo : itemList) {
    Assert.assertTrue(vo.getName() != null,     "name不能為空");
    Assert.assertTrue(vo.getPrice() != null,    "price不能為空");
    }
    }
      說(shuō)明:
      顧名思義,就是在用例中簡(jiǎn)單調(diào)用一下被測(cè)方法(method),主要是為了跑通流程,拒絕Block級(jí)別問(wèn)題
      實(shí)踐中,推薦 伴隨著功能開(kāi)發(fā),隨時(shí)編寫(xiě)冒煙用例,功能代碼與冒煙用例一起提交代碼庫(kù)
      對(duì)于一些復(fù)雜的功能,功能開(kāi)發(fā)的過(guò)程也是一個(gè)持續(xù)重構(gòu)的過(guò)程,編碼前期完成的冒煙用例,可以有效起到安全網(wǎng)作用
      Δ冒煙型用例 – 乙
    @Test(description = "enter_and_leave_market_冒煙_進(jìn)入與離開(kāi)超市")
    public void test_enter_and_leave_market_smoke() {
    Custom tom = new Custom("Tom");
    tom.enterMarket();
    Assert.assertTrue(Custom.isAtMarket(tom),   "tom應(yīng)該在超市內(nèi)");
    tom.leaveMarket();
    Assert.assertFalse(Custom.isAtMarket(tom),  "tom應(yīng)該不在超市");
    }
      說(shuō)明:
      這個(gè)用例把進(jìn)入超市及離開(kāi)超市這兩個(gè)(強(qiáng)相關(guān)的)接口串起來(lái)了,目的在于走通流程
      實(shí)踐中,建議 將新模塊(函數(shù))與其強(qiáng)相關(guān)的模塊(函數(shù))盡早進(jìn)行簡(jiǎn)單的集成測(cè)試以提前發(fā)現(xiàn)一些問(wèn)題

     Δ正常流程用例
    @Test(description = "addToCart_正常流程_往購(gòu)物車內(nèi)添加各種類型數(shù)目的商品", dataProvider = "test_addToCart_normal_data")
    @Rollback
    public void test_addToCart_normal(String caseNote, long itemId, int count) {
    Custom tom = new Custom("Tom");
    this.setCustom(tom);
    cartBean.addToCart(itemId, count);
    Item item = tom.getCart.getItems.get(0);    // 獲取購(gòu)物車中的第一項(xiàng)商品
    Assert.assertEquals(item.getId,      itemId,  "itemId is wrong");
    Assert.assertEquals(item.getCount,   count,   "count is wrong");
    }
    @DataProvider
    public Object[][] test_addToCart_normal_data() {
    return new Object[][] {
    // caseNote,                    itemId,     count
    {"Milk  - just a dozen",        39001L,     12,  },
    {"Bread - huge number",         116001L,    999},
    {"Bean  - less then 10",        1018100L,   2},
    };
    }
      說(shuō)明:
      這個(gè)示例代碼演示了如何測(cè)試addToCart()的功能,假定這個(gè)方法內(nèi)部有十分復(fù)雜的業(yè)務(wù)邏輯,我們須要覆蓋各種場(chǎng)景
      可以看到,正常流程用例與冒煙用例其實(shí)差不多,不同的是,正常流程用例會(huì)覆蓋更多分支,冒煙用例則一般是走通流程就行
      這個(gè)用例使用了@Rollback標(biāo)簽,用例執(zhí)行后會(huì)回滾數(shù)據(jù),而不會(huì)真正往數(shù)據(jù)庫(kù)內(nèi)插入數(shù)據(jù);這個(gè)功能十分有用,可以大大減少數(shù)據(jù)準(zhǔn)備與清理的工作;至于@Rollback背后的實(shí)現(xiàn)原理,此處暫時(shí)按下不表
      測(cè)試參數(shù)使用TestNg的@DataProvider組織起來(lái),每一行都是一組測(cè)試數(shù)據(jù),覆蓋一種測(cè)試分支
      測(cè)試參數(shù)的第一列建議設(shè)置為caseNote,簡(jiǎn)單闡述用例的意圖,可以有效提升用例可讀性
      Δ異常流程用例
    @Test(description = "addToCart_異常流程_往購(gòu)物車內(nèi)添加參數(shù)非法的商品", dataProvider = "test_addToCart_error_data")
    @Rollback
    public void test_addToCart_error(String caseNote, long itemId, int count, int expectedErrorCode) {
    Custom tom = new Custom("Tom");
    this.setCustom(tom);
    try {
    cartBean.addToCart(itemId, count);
    Assert.fail();
    } catch (Exception e) {
    Assert.assertEquals(e.getErrorCode, expectedErrorCode);
    }
    }
    @DataProvider
    public Object[][] test_addToCart_error_data() {
    return new Object[][] {
    // caseNote,                        itemId,     count,  expectedErrorCode
    {"iPad       - 0 count",            39001L,     0,      Cart.ZERO_COUNT},
    {"MacBookPro - more then stock",    116001L,    1024,   Cart.MORE_THAN_STOCK},
    {"no such item",                    0L,         1L,     Cart.NO_SUCH_ITEM}
    };
    }
      說(shuō)明:
      如果不同的異常輸入會(huì)有相應(yīng)的 errorCode 的話, 可以把errorCode當(dāng)成測(cè)試數(shù)據(jù)的一項(xiàng)參數(shù)傳進(jìn)去

     Δ特殊場(chǎng)景 & 復(fù)雜流程
      個(gè)別特殊場(chǎng)景,不方便使用@DataProvider合并的復(fù)雜流程,可以單獨(dú)創(chuàng)建一個(gè)用例進(jìn)行測(cè)試,函數(shù)命名的時(shí)候注明一下,例如:
      test_addToCart_error_withoutEnoughMoney() – 鈔票不夠
      test_addToCart_normal_mergeMultiCarts() – 合并多個(gè)購(gòu)物車
      Δ前事不忘,后事之師
      出過(guò)Bug的地方(及其周邊)補(bǔ)充單元測(cè)試覆蓋,由單元測(cè)試幫你記住前事 – test_funcOne_issue12345_bugfix()
      用例編寫(xiě)流程
      用例編寫(xiě)順序:
      開(kāi)發(fā)新功能時(shí),同步編寫(xiě)冒煙測(cè)試,用于自測(cè)及調(diào)試,功能代碼與冒煙用例一起提交 – test_funcOne_smoke()
      稍晚,補(bǔ)充更多分支覆蓋的正常流程用例,相當(dāng)于進(jìn)行又一輪自測(cè) – test_funcOne_normal()
      最后,補(bǔ)充異常流程和特殊(復(fù)雜)場(chǎng)景用例 – test_funcOne_error() & test_funcOne_specialScenario()
      之所以這樣安排,一個(gè)很重要的原因是希望 保持主干及正常流程的暢通,確保開(kāi)發(fā)及測(cè)試不會(huì)Block
      此外:
      盡量把單個(gè)開(kāi)發(fā)任務(wù)切分成多個(gè)小功能點(diǎn),頻繁提交,穩(wěn)扎穩(wěn)打,配合Jenkins & Sonar,多跑單元測(cè)試和靜態(tài)代碼檢查,問(wèn)題早發(fā)現(xiàn)早處理
      前事不忘,后事之師,出過(guò)Bug的地方補(bǔ)充單元測(cè)試
      補(bǔ)遺
      單元測(cè)試與靜態(tài)代碼檢查(static analysis, SA)是一對(duì)好基友,兩者可以統(tǒng)一顯示在Sonar上面,在實(shí)踐中往往一起考察
      關(guān)于Sonar,實(shí)乃居家必備,代碼度量之利器,以后會(huì)另外講述,這里先貼個(gè)圖:
    相關(guān)文章:

    posted on 2013-12-13 09:49 順其自然EVO 閱讀(214) 評(píng)論(0)  編輯  收藏 所屬分類: selenium and watir webdrivers 自動(dòng)化測(cè)試學(xué)習(xí)

    <2013年12月>
    24252627282930
    1234567
    891011121314
    15161718192021
    22232425262728
    2930311234

    導(dǎo)航

    統(tǒng)計(jì)

    常用鏈接

    留言簿(55)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    搜索

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    主站蜘蛛池模板: 久久精品电影免费动漫| 无码久久精品国产亚洲Av影片| 久久爰www免费人成| 美女羞羞视频免费网站| 亚洲情A成黄在线观看动漫软件| 久久九九亚洲精品| 亚洲国产黄在线观看| 大学生美女毛片免费视频| 精品国产免费人成电影在线观看| 两个人日本WWW免费版| 黄色三级三级免费看| 亚洲精品欧美综合四区| 亚洲区视频在线观看| 亚洲福利秒拍一区二区| 久久精品国产亚洲AV麻豆王友容| 国产亚洲色视频在线| av在线亚洲欧洲日产一区二区| 国产在线19禁免费观看国产| 成人午夜18免费看| 九九精品免费视频| 国产一卡二卡3卡四卡免费 | 亚洲国产成人精品久久久国产成人一区二区三区综 | 亚洲av无一区二区三区| 国产精品亚洲精品青青青| 亚洲国产精品成人综合久久久 | 久久免费观看视频| 亚洲黄片手机免费观看| 老司机免费午夜精品视频| 自拍偷自拍亚洲精品播放| 在线观看国产一区亚洲bd| 亚洲精品无码av片| 亚洲精品无播放器在线播放| 亚洲AV成人一区二区三区观看| 亚洲av中文无码乱人伦在线观看| 亚洲精品无码av中文字幕| 亚洲大尺度无码无码专线一区| 久久亚洲中文无码咪咪爱| 色噜噜狠狠色综合免费视频 | 九月丁香婷婷亚洲综合色| 亚洲AV永久无码精品水牛影视| 亚洲国产婷婷六月丁香|