qileilove

          blog已經(jīng)轉(zhuǎn)移至github,大家請訪問 http://qaseven.github.io/

          代碼測試(CodeTest)

          1.  什么是代碼測試?與傳統(tǒng)的功能和接口測試有什么不同?
            代碼測試的立足點是Code,是基于代碼基礎(chǔ)之上的,而傳統(tǒng)的功能測試和接口測試是基于應(yīng)用的,必須對應(yīng)的測試系統(tǒng)是在運行中的。
            代碼測試不會特別注重接口測試的可持續(xù)性集成。
            代碼測試的特點是快捷高效準(zhǔn)確的完成測試工作,快速推進產(chǎn)品的迭代。
            2.  Code Test 的方法:
            (1)  代碼走讀和review
            適合場景:邏輯相對簡單,有較多的邊界值。
            方法介紹:直接查看和閱讀代碼,檢驗邏輯是否正確。
            (2)  代碼debug與代碼運行中測試
            適合場景:數(shù)據(jù)構(gòu)造比較困難,特殊的場景覆蓋。
            方法介紹:1.直接在debug代碼過程中查看數(shù)據(jù)流走向,校驗邏輯。
            2.在debug過程中直接將變量的值或者對象的值直接改成想要的場景
            (3)  私有方法測試
            適合場景:需要測試的類的復(fù)雜邏輯處理是放在一個特定的方法中,而且該方法中沒有使用到其他引用的bean
            方法介紹:通過反射的方式調(diào)用方法,進行測試。
            例子:
            假設(shè)有一個待測試的類叫MyApp,有一個私有方法叫g(shù)etSortList, 參數(shù)是一個整形List。
          /**
          * Created by yunmu.wgl on 2014/7/16.
          */
          public class MyApp {
          private List  getSortList(List<Integer> srcList){
          Collections.sort(srcList);
          return srcList;
          }
          }
            那么測試類的代碼如下:
          /**
          * Created by yunmu.wgl on 2014/7/16.
          */
          public class MyAppTest {
          @Test
          public  void testMyApp() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
          Class clazz = MyApp.class;
          Method sortList = clazz.getDeclaredMethod("getSortList",List.class); //獲取待測試的方法
          sortList.setAccessible(true); //私有方法這個是關(guān)鍵
          List<Integer> testList = new ArrayList<Integer>();//構(gòu)造測試數(shù)據(jù)
          testList.add(1);
          testList.add(3);
          testList.add(2);
          MyApp myApp = new MyApp(); // 新建一個待測試類的對象
          sortList.invoke(myApp,testList); //執(zhí)行測試方法
          System.out.println(testList.toString()); //校驗測試結(jié)果
          }
          }
           (4)  快速搭建測試腳本環(huán)境
            適合場景:待測試的方法以hsf提供接口方法,或者需要測試的類引入了其他bean 配置。
            方法介紹:直接在開發(fā)工程中添加測試依賴,主要是junit,如果是需要測試hsf接口,則加入hsf的依賴,如果需要使用itest的功能,加入itest依賴。
            Junit 的依賴一般開發(fā)都會加,主要看下junit的版本,最好是4.5 以上
            HSF的測試依賴:以前的hsfunit 和hsf.unit 最好都不要使用了。
            <dependency>
            <groupId>com.taobao.hsf</groupId>
            <artifactId>hsf-standalone</artifactId>
            <version>2.0.4-SNAPSHOT</version>
            </dependency>
            Hsf 接口測試代碼示例:
            // 啟動HSF容器,第一個參數(shù)設(shè)置taobao-hsf.sar路徑,第二個參數(shù)設(shè)置HSF版本
            HSFEasyStarter.start("d:/tmp/", "1.4.9.6");
            String springResourcePath = "spring-hsf-uic-consumer.xml";
            ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(springResourcePath);
            UicReadService uicReadService = (UicReadService) ctx.getBean("uicReadService");
            // 等待相關(guān)服務(wù)的地址推送(等同于sleep幾秒,如果不加,會報找不到地址的錯誤)
            ServiceUtil.waitServiceReady(uicReadService);
            BaseUserDO user = uicReadService.getBaseUserByUserId(10000L, "detail").getModule();
            System.out.println("user[id:10000L] nick:" + user.getNick());
            Hsf bean的配置示例:
            <beans>
            <bean name="uicReadService" class="com.taobao.hsf.app.spring.util.HSFSpringConsumerBean"
            init-method="init">
            <property name="interfaceName" value="com.taobao.uic.common.service.userinfo.UicReadService" />
            <property name="version" value="1.0.0.daily" />
            </bean>
            </beans>
            Itest的依賴:這個版本之前修復(fù)了較多的bug。
            <dependency>
            <groupId>com.taobao.test</groupId>
            <artifactId>itest</artifactId>
            <version>1.3.2.1-SNAPSHOT</version>
            <dependency>
            (5)  程序流程圖校驗
            適合場景:業(yè)務(wù)流程的邏輯較為復(fù)雜,分支和異常情況很多
            方法介紹:根據(jù)代碼邏輯畫出業(yè)務(wù)流程圖,跟實際的業(yè)務(wù)邏輯進行對比驗證,是否符合預(yù)期。
            (6)  結(jié)對編程
            適合場景:代碼改動較小,測試和開發(fā)配對比較穩(wěn)定
            方法介紹:開發(fā)修改完代碼后,將修改部分的邏輯重復(fù)給測試同學(xué),測試同學(xué)review 開發(fā)同學(xué)講述的邏輯是否和代碼的邏輯一致。
            3.   具體操作步驟:
            (1)  checkout代碼,在接手項目和日常后第一件事情是checkout 對應(yīng)的應(yīng)用的代碼
            (2)  了解數(shù)據(jù)結(jié)構(gòu)與數(shù)據(jù)存儲關(guān)系:了解應(yīng)用的數(shù)據(jù)對象和數(shù)據(jù)庫的表結(jié)構(gòu)及存儲關(guān)系。
            (3)  了解代碼結(jié)構(gòu), 主要搞清楚代碼的調(diào)用關(guān)系。
            (4)  了解業(yè)務(wù)邏輯和代碼的關(guān)系:業(yè)務(wù)邏輯肯定是在代碼中實現(xiàn)的,找到被測試的業(yè)務(wù)邏輯對應(yīng)的代碼,比較常見的是通過url 或者接口名稱等。
            如果是webx框架的可以根據(jù)http請求找到對應(yīng)的代碼,如果是其他框架的也可以通過http請求的域名在配置文件中找到對應(yīng)的代碼。
            (5)  閱讀相關(guān)代碼,了解數(shù)據(jù)流轉(zhuǎn)過程。
            (6)  Review 代碼,驗證條件,路徑覆蓋。
            (7)  復(fù)雜邏輯可以選用寫腳本測試或者私有方法測試,或者畫出流程圖。
            4.  代碼測試的常見測試場景舉例:
            (1)  條件,邊界值,Null 測試:
            復(fù)雜的多條件,多邊界值如果要手工測試,會測試用例非常多。而且null值的測試往往構(gòu)造數(shù)據(jù)比較困難。
            例如如下的代碼:
          if (mm.getIsRate() == UeModel.IS_RATE_YES) {
          float r;
          if (value != null && value.indexOf(‘.’) != -1) {
          r = currentValue – compareValue;
          } else {
          r = compareValue == 0 ? 0 : (currentValue – compareValue) / compareValue;
          }
          if (r >= mm.getIncrLowerBound()) {
          score = mm.getIncrScore();
          } else if (r <= mm.getDecrUpperBound()) {
          score = mm.getDecrScore();
          }
          mr.setIncreaseRate(formatFloat(r));
          } else {
          // 目前停留時間為非比率對比
          if (currentValue – compareValue >=mm.getIncrLowerBound()) {
          score = mm.getIncrScore();
          } else if (currentValue – compareValue <= mm.getDecrUpperBound()) {
          score = mm.getDecrScore();
          }
          }
          (2)  方法測試
            某個方法相對比較獨立,但是是復(fù)雜的邏輯處理
            例如下面的代碼:
          private void filtSameItems(List<SHContentDO> contentList) {
          Set<Integer> sameIdSet = new TreeSet<Integer>();
          Set<Integer> hitIdSet = new HashSet<Integer>();
          for (int i = 0; i < contentList.size(); i++) {
          if (sameIdSet.contains(i) || hitIdSet.contains(i)) {
          continue;
          }
          SHContentDO content = contentList.get(i);
          List<Integer> equals = new ArrayList<Integer>();
          equals.add(i);
          if ("item".equals(content.getSchema())) {
          for (int j = i + 1; j < contentList.size(); j++) {
          SHContentDO other = contentList.get(j);
          if ("item".equals(other.getSchema()) && content.getReferItems().equals(other.getReferItems())) {
          equals.add(j);
          }
          }
          }
          if (equals.size() > 1) {
          Integer hit = equals.get(0);
          SHContentDO hitContent = contentList.get(hit);
          for (int k = 1; k < equals.size(); k++) {
          SHContentDO other = contentList.get(k);
          if (hitContent.getFinalScore() == other.getFinalScore()) {
          long hitTime = hitContent.getGmtCreate().getTime();
          long otherTime = other.getGmtCreate().getTime();
          if (hitTime > otherTime) {
          hit = equals.get(k);
          hitContent = other;
          }
          } else {
          if (hitContent.getFinalScore() < other.getFinalScore()) {
          hit = equals.get(k);
          hitContent = other;
          }
          }
          }
          for (Integer tmp : equals) {
          if (tmp != hit) {
          sameIdSet.add(tmp);
          }
          }
          hitIdSet.add(hit);
          }
          }
          Integer[] sameIdArray = new Integer[sameIdSet.size()];
          sameIdSet.toArray(sameIdArray);
          for (int i = sameIdArray.length - 1; i >= 0; i--) {
          contentList.remove((int) sameIdArray[i]);
          }
          }

          posted on 2014-10-30 10:46 順其自然EVO 閱讀(592) 評論(0)  編輯  收藏 所屬分類: 測試學(xué)習(xí)專欄

          <2014年10月>
          2829301234
          567891011
          12131415161718
          19202122232425
          2627282930311
          2345678

          導(dǎo)航

          統(tǒng)計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 墨脱县| 微山县| 讷河市| 天全县| 大足县| 高唐县| 施甸县| 嘉祥县| 叙永县| 渭源县| 五台县| 罗定市| 边坝县| 德阳市| 开平市| 万载县| 武宁县| 三明市| 奉贤区| 乌鲁木齐县| 高阳县| 罗城| 湘潭县| 珲春市| 贞丰县| 海宁市| 西安市| 安溪县| 永胜县| 东丽区| 淮滨县| 莫力| 固镇县| 安化县| 东乡族自治县| 庆安县| 晋江市| 连城县| 五河县| 宜兴市| 长子县|