qileilove

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

          敏捷開發(fā)和測試中重現(xiàn)缺陷和驗證缺陷的解決方案(3)

          簡介:在作為系列的最后一篇覆蓋的部分是缺陷生命周期的最后一個環(huán)節(jié),缺陷的驗證。本文主要描述了如何通過 Rational Team Concert(RTC)、Rational Quality Manager(RQM)及 IBM Workload Deployer(IWD)實現(xiàn)缺陷驗證的自動化,而且筆者通過一個 RTC web 插件來展現(xiàn)自動化頁面。

            背景

            系列前兩篇中我們描述了如何用 IBM 產(chǎn)品幫助開發(fā)人員快速重現(xiàn)缺陷問題,下面本文主要描述一下我們是如何使用 IBM 產(chǎn)品加速缺陷驗證過程的。

            在缺陷驗證的過程中,測試人員需要完成一下幾個任務(wù):

            ● 定位可驗證的缺陷 (Verifiable Defect)

              ▲ 可驗證的缺陷是指缺陷對應(yīng)的產(chǎn)品代碼變動已經(jīng)被開發(fā)人員提交并包含在產(chǎn)品最新版本中。

              ▲ 定位的范圍一般包括

                → 測試人員自己提交的缺陷(Created by)

                → 由其他人員提交的,需要測試人員關(guān)注的缺陷(Subscribed by)

              ▲ 測試人員一般需要針對每個關(guān)注的缺陷查看是否相應(yīng)的代碼變更已經(jīng)包括在最新產(chǎn)品版本中。

            ● 快速部署缺陷驗證的測試環(huán)境

              ▲ 環(huán)境準備一直是比較耗時的部分,不過這里我們可以借助在第一篇中我們創(chuàng)建的重現(xiàn)缺陷用的 IWD 中的虛擬系統(tǒng)模式 (Virtual System Pattern)。

            ● 調(diào)用對應(yīng)的測試用例執(zhí)行

              ▲ 測試人員需要找到對應(yīng)的測試用例,在最新產(chǎn)品版本中重現(xiàn)執(zhí)行。

            ● 更新缺陷狀態(tài)和信息

              ▲ 根據(jù)最新的測試執(zhí)行結(jié)果,可以判斷缺陷是否還存在,從而更新缺陷狀態(tài)和信息記錄。

            本文主要解決的問題

            ● 如何快速定位可驗證的缺陷

            ● 把缺陷驗證環(huán)節(jié)自動化,自動化內(nèi)容包括:

              ▲ 準備測試環(huán)境

              ▲ 執(zhí)行測試用例

              ▲ 更新缺陷狀態(tài)和信息

            ● 更好的用戶體驗

              ▲ 現(xiàn)在每個團隊都會在不同程度上通過自動化工具來解決上述問題。由于上述工作涉及存儲不同信息的軟件系統(tǒng),測試人員就需要登陸不同的系統(tǒng)采取相應(yīng)的操作,例如:

                → 缺陷管理系統(tǒng):開發(fā)和測試人員在這里可以更改缺陷的內(nèi)容和狀態(tài)。

                → 產(chǎn)品 build 管理系統(tǒng):每個產(chǎn)品在正式發(fā)布前,內(nèi)部的研發(fā)解決都會采用某個軟件或系統(tǒng)對產(chǎn)品代碼進行管理并且對內(nèi)部發(fā)布產(chǎn)品非正式版本 (Build) 用于開發(fā)和測試。產(chǎn)品 Build 管理系統(tǒng)會記錄每個 Build 所包含的代碼變動,也會同時記錄這一代碼變動是由哪個缺陷引起的。

                → IT 環(huán)境管理系統(tǒng):這一系統(tǒng)通常會為開發(fā)測試人員提供可用的環(huán)境。在某些團隊中會通過不同的軟件來調(diào)用 IT 環(huán)境管理系統(tǒng)來實現(xiàn)不同程度的自動化環(huán)境部署。

                → 測試管理系統(tǒng):存儲測試用例,測試結(jié)果和測試計劃等內(nèi)容。

              ▲ 所以開發(fā)和測試人員在完成缺陷驗證工作的過程中,需要登錄各種不同的軟件系統(tǒng),而沒有統(tǒng)一入口的使用方式會帶來不好的用戶體驗。

            實現(xiàn)框架

          圖 1. 實現(xiàn)框架



          框架中有四個主要的部分:

            1、搜索:這個部分負責(zé)跟缺陷管理系統(tǒng)和產(chǎn)品 Build 管理系統(tǒng)交互獲得跟用戶有關(guān)的可驗證缺陷信息、對應(yīng)的產(chǎn)品 Build 信息和測試用例的信息。

            2、部署環(huán)境:負責(zé)接收搜索部分提供的結(jié)果,準備測試環(huán)境。框架中給出了兩個部署環(huán)境的方案,第一個是創(chuàng)建一個新的測試環(huán)境;第二個是查找跟這個用戶有關(guān)的已經(jīng)存在的測試環(huán)境,并把產(chǎn)品的最新 Build 部署到這個環(huán)境中。這里第二個方案也是為了能夠更好地重用測試資源,以免造成浪費。

            3、測試執(zhí)行:根據(jù)搜索部分提供測試用例,調(diào)用對應(yīng)的自動化測試用例腳本進行驗證。

            4、狀態(tài)更新:根據(jù)測試執(zhí)行的結(jié)果自動更新缺陷的狀態(tài)和內(nèi)容。

            框架中提到的不同軟件系統(tǒng),每個團隊可以針對自己的實例完成實現(xiàn)。

            實現(xiàn)部分 1:搜索可驗證的缺陷

            在 RTC 中我們的實現(xiàn)是開始于 RTC 中的一個缺陷查詢 (Query),用戶可以自己定義一個缺陷查詢包括那些狀態(tài)時 Resolved 的缺陷。

          圖 2. RTC 中的缺陷查詢

            清單 1. 引用 RTC 中用戶自定義的缺陷查詢

            搜索條件包括三個方面,

            ● 產(chǎn)品– 由于 RTC 同一個項目中可能會涉及多個產(chǎn)品的缺陷記錄,而一個用戶又有可能會對多個產(chǎn)品的缺陷負責(zé),所以產(chǎn)品作為第一個篩選條件。

            ● 產(chǎn)品版本– 由于 RTC 同一個項目中可能會涉及同一個產(chǎn)品的不同版本的開發(fā)以及缺陷記錄,而一個用戶又有可能會工作于不同的產(chǎn)品版本。

            ● 環(huán)境 -- 在 RTC 中可以為不同的項目缺陷記錄定義不同的字段,這里可以定義環(huán)境的信息。(如圖3)

          圖 3. RTC 缺陷中的環(huán)境字段

            根據(jù)用戶自定義的缺陷查詢和選定的三個篩選條件,我們可以完成第一次篩選,得到待驗證的缺陷列表。下面就需要去版本控制系統(tǒng)中查找當(dāng)前產(chǎn)品版本中包含哪些待驗證的缺陷。

          圖 4. 篩選可驗證的缺陷

            由于本文作者沒有直接使用 RTC 作為版本控制軟件,而是采用其他軟件進行版本控制,所以這里沒有具體介紹圖 4 中代碼的實現(xiàn)。










           實現(xiàn)部分 2:缺陷驗證環(huán)境的部署

            由于我們在系列第二篇中曾經(jīng)提到對 RTC 中存儲的缺陷添加"IWD Pattern"字段,用于存儲虛擬系統(tǒng)模式的名字,這里可以直接通過 RTC RESTAPI 獲得虛擬系統(tǒng)模式名稱,然后通過 IWD 的命令行工具 (Command Line Tool) 或者 RESTAPI 在對應(yīng)的 IWD 服務(wù)器上創(chuàng)建缺陷驗證環(huán)境。

            IWD 提供的命令行工具可以直接從 IWD 的登陸界面上下載:

          圖 5. IWD 登陸界面中命令行工具下載頁面

           

          圖 6. IWD 命令行工具本地文件結(jié)構(gòu)

            IWD 命令行工具是通過 python 腳本調(diào)用 IWD RESTAPI 實現(xiàn)具體功能的,工具中的 readme 文件具體描述了如何調(diào)用 python 腳本,或者讀者也可以從參考資源中提供的鏈接學(xué)習(xí)如何調(diào)用。以下是兩個 python 腳本,在部署缺陷環(huán)境前先查找缺陷中記錄的虛擬系統(tǒng)模式是否包含在這個 IWD 服務(wù)器中,如果在則繼續(xù)部署這個虛擬系統(tǒng)模式為一個虛擬機環(huán)境。

            清單 2. 查看 IWD 服務(wù)器上所有虛擬系統(tǒng)模式信息

          #
          # For each pattern returned, the name of the pattern is presented
          #
          import ConfigParser
          import threading, time, csv, random

          # get all the vsystems associated with a pattern
          # this emulates the user clicking on the "Systems" selection in the tree view
          def get_systems(pattern, fname, fhandle):
              nsystems = 0
              start = time.time()
              nSystems = len(pattern.virtualsystems)
              for cnt in range (nSystems):
                  try:
                      system = pattern.virtualsystems[cnt]
                  except:
                      break        
              finish = time.time()
              fname.writerow([time.strftime("%m/%d/%Y"), time.strftime("%H:%M:%S"),'system',
                               nSystems, (finish-start)])
              fhandle.flush()
              
          # get all the patterns
          # this emulates the user clicking on the "Patterns" selection in the tree view
          def get_patterns(fname, fhandle):
              start = time.time()
              patterns = deployer.patterns
              finish = time.time()
              fname.writerow([time.strftime("%m/%d/%Y"), time.strftime("%H:%M:%S"),'pattern', 
                             len(patterns), (finish-start)])
              fhandle.flush()
              
              for pattern in patterns:
                  if (len(pattern.virtualsystems) > 0):
                      time.sleep(random.randint(1, 10))            
                      get_systems(pattern, fname, fhandle)

          ######
          config = ConfigParser.RawConfigParser()
          config.read('listPatterns.cfg')

          try:
              output = '%s_%s.csv' % (config.get('Main', 'outfile'),time.strftime("%Y%m%d@%H%M%S"))
              interval = config.getint('Main', 'interval')
              duration = config.getint('Main', 'duration')
          except ConfigParser.Error:
              print "Error reading config file"
              sys.exit

          fhandle = open(output, 'w')
          fname = csv.writer(fhandle, delimiter=',')
          fname.writerow(['date', 'time', 'type', 'number','duration'])
          fhandle.flush()

          print 'Running ...'
          print 'Output File: %s\tDuration: %d\tInterval: %d' % (output, duration, interval)

          end_time = time.time()+(60*duration)
          while (end_time > time.time()):
              start = time.time()
              time.sleep(random.randint(1, 10))
              get_patterns(fname, fhandle)
              
              # only sleep the remainder of the interval
              time.sleep((time.time()+interval) - start)
              
          print 'Completed on %s at %s' % (time.strftime("%m/%d/%Y"), time.strftime("%H:%M:%S"))
          fhandle.close()


           清單 3. 部署制定的虛擬系統(tǒng)模式

          import time, threading, Queue, csv
             
          # deploy the images for performance throughput
          class waitfor(threading.Thread):
              def __init__(self, system, log_q):
                  self.system = system
                  self.log_q = log_q
                  threading.Thread.__init__(self)
                      
              def run(self):
                  start = time.clock()
                  self.system.waitFor()
                  finish = time.clock()           
                  self.log_q.put_nowait([time.strftime("%m/%d/%Y"), time.strftime("%H:%M:%S"),
                                        self.system.name,self.system.currentstatus,(finish-start)])
              
          def run_test(instances, fname):
              log_q = Queue.Queue()
              threads = []
              for instance in range (int(instances)):
                  virtualsystem = None
                  sysName = '%s-%s-%s-%d' % (pfx, time.strftime("%Y%m%d"),time.strftime("%H%M5%S"),
                                             instance+1)
                  print 'deploying virtual system: %s' % sysName
                  
                  createParms['name'] = sysName
                  virtualsystem = deployer.virtualsystems << createParms
                  sys = waitfor(virtualsystem, log_q)
                  sys.start()
                  threads.append(sys)
              
              #wait until all are done
              for thd in threads:
                  thd.join()
              
              # write out the results
              fname = csv.writer(open(fname, 'w'))
              fname.writerow(['date', 'time', 'system_name','status','duration'])
              for xx in range(log_q.qsize()):
                  data = log_q.get()
                  fname.writerow(data)

          #################################################################
          # select pattern to deploy
          instances = raw_input('number of instances to create: ')
          pfx = raw_input('prefix for created systems: ')
          output = raw_input('results file (** will be overwritten **): ')
          createParms = {}

          # default parameters
          createParms['*.script-4.CHEF_NODE'] = 'devops_default'
          createParms['*.script-4.DEPS_FILE_URL'] = '/tmp/devops_install/media/Deps-devops_services'
          createParms['*.script-4.CHEF_NODE_ATTR'] = 
              '\"devops_server\"\:
              {\"app_source\"\:\"file:///tmp/devops_install/media/devops_services_app.zip\"}, 
              \"ram\"\:{\"server_url\"\:
              \"http://devops.rtp.raleigh.ibm.com/downloads/RAM-Server-7.5.1.1-Linux64.zip\",
              \"persist_url\"
              \:\"http://devops.rtp.raleigh.ibm.com/downloads/RAM-Data-7.5.1.1.tar.gz\",
              /\"database_url\"\:
              \"http://devops.rtp.raleigh.ibm.com/downloads/RAM-Database-7.5.1.1.tar.gz\"},
              \"db2\"\:{
              \"host_server_url\"\:\"http://devops.rtp.raleigh.ibm.com/downloads\"},
              \"jruby\"\:{\"download_url\"\:\"http://devops.rtp.raleigh.ibm.com/downloads/\"}'
          createParms['cloud'] = deployer.clouds[0]

          # select the performance pattern to deploy
          pattern = None
          while not pattern:
              i = 1
              for p in deployer.patterns:
                  print '%d. %s' % (i, p.name)
                  i = i + 1
              x = raw_input('select the test pattern to deploy: ')
              try:
                  pattern = deployer.patterns[int(x) - 1]
              except:
                  # try again
                  pass
          createParms['pattern'] = pattern

          #start deploying
          started = time.strftime("%m/%d/%Y at %H:%M:%S")
          run_test(instances, output)    
          completed = time.strftime("%m/%d/%Y at %H:%M:%S")

          print '#############   test summary  #######################'
          print 'Started on: %s\tCompleted on: %s' % (started, completed)
          print 'Images deployed: %s' % instances

            實現(xiàn)部分 3:測試執(zhí)行

            測試執(zhí)行的時候我們需要調(diào)用 RQM 的命令行執(zhí)行工具 (Command Line Execution Tool),這個工具是跟著 RQM 同時發(fā)布在 Jazz.net 上的,具體下載請看參考資源中提供的鏈接。

            RQM 命令行執(zhí)行工具是我們可以方便的執(zhí)行測試,通過 RQM RESTAPI 啟動測試執(zhí)行記錄 (Test Execution Record) 的運行。在運行測試執(zhí)行時需要提供以下信息:

            ● RQM url – https://hostname:9443/qm

            ● 用戶名和密碼 -- 使用這個用戶名允許運行相應(yīng)的測試執(zhí)行記錄

            ● 項目– 測試用例所在的 RQM 中的測試項目

            ● 測試執(zhí)行記錄的 id

            ● 測試執(zhí)行記錄關(guān)聯(lián)的腳本的 id

            ● 執(zhí)行適配器 (Adapter) 的 id

              ▲ 執(zhí)行適配器是 RQM 提供的用以連接并操作具體測試腳本的功能,常用的適配器包括 Rational Functional Tester、Rational Performance Tester、Rational Build Forge 以及其他更多第三方廠商和開源工具的適配器。用戶也可以自己編寫適配器。

            ● 執(zhí)行時需要的參數(shù)

            通過命令行調(diào)用后執(zhí)行結(jié)果是會輸出到命令行的,也可以直接輸出到文件,用于后續(xù)操作。


          實現(xiàn)部分 4:自動化中注意事項

            要把整個流程自動化需要用到流程工具,可以用開源的 ant 或者使用 IBM Rational Build Forge。

            這里主要介紹幾個重點:

            1、測試用例相關(guān)信息獲得

            a)缺陷可以通過 RTC 與 RQM 之間的 OSLC 關(guān)聯(lián)關(guān)系連接 RQM 中的測試執(zhí)行結(jié)果 (Test Execution Result),測試執(zhí)行結(jié)果是測試執(zhí)行記錄 (Test Execution Record) 的執(zhí)行結(jié)果。

            b)然后我們可以從缺陷中獲得測試執(zhí)行結(jié)果的 url,經(jīng)過分析我們可以獲得 RQM 項目名稱,測試執(zhí)行結(jié)果 id 等信息,用于調(diào)用 RQM 命令行執(zhí)行工具。

            2、缺陷驗證環(huán)境信息的傳遞

            a)缺陷驗證環(huán)境是我們通過部署虛擬系統(tǒng)模式生成的新的虛擬機,所以 ip、hostname、用戶名和密碼都是新的。而在驗證系列第二篇中提到的 WAS 賣花網(wǎng)站中遇到的缺陷,我們需要傳送新的 url 地址給 RFT 腳本。

            b)在調(diào)用 RQM 命令行執(zhí)行工具的時候就需要傳輸參數(shù)

            清單 4. RQM 命令行調(diào)用附參數(shù)

          c:\IBM\java60\bin\java -jar RQMExecutionTool.jar -tcerId=1 -projectName=QM1 
                                 -publicURI=https://paul801beta:9443/qm -user=paul 
                                 -password=passw0rd -exitOnComplete=true 
                                 -variables=host:clmsvr-sjy.cn.ibm.com

              c)RFT 中接受參數(shù)的腳本如下

            清單 5. RFT 腳本

          import com.rational.test.ft.script.IParameter;
          import com.rational.test.ft.script.IVariablesManager;
          public class SampleScript extends SampleScriptHelper
          {
              /**
               * Script Name   : <b>SampleScript</b>
               * Generated     : <b>Dec 10, 2012 1:44:05 PM</b>
               * Description   : Functional Test Script
               * Original Host : WinNT Version 5.1  Build 2600 (S)
               *
               * @since  2012/12/10
               * @author Administrator
               */
              public void testMain(Object[] args)
              {
                  //接收參數(shù)的定義
                  IVariablesManager manager = getVariablesManager();
                  IParameter host = manager.getInputParameter("host");
                  
                  
                  startApp("http://" + host.getValue() + ":9081/PlantsByWebSphere/");
                  
                  // HTML Browser
                  // Document: Plants by WebSphere: 
                  // http://clmsvr-sjy.cn.ibm.com:9081/PlantsByWebSphere/
                  // Document: http://clmsvr-sjy.cn.ibm.com:9081/PlantsByWebSphere/promo.html
                  image_bonsaiTree().click();
                  // Document: 
                  // http://clmsvr-sjy.cn.ibm.com:9081/PlantsByWebSphere/servlet/ShoppingServlet?
                  //      action=productdetail&itemID=T0003
                  browser_htmlBrowser(document_plantsByWebSphere(),DEFAULT_FLAGS).inputChars("abc");
                  button_addToCart().click();
              }
          }

            這里提示一下 RQM 命令行執(zhí)行工具也提供了 ant 任務(wù)調(diào)用,方便把執(zhí)行測試這部分集成到自動化的流程中。

            實現(xiàn)部分 5:Jazz 插件的開發(fā)

            Jazz 插件的開發(fā)與 Eclipse 插件開發(fā)模式是一致的,Jazz 平臺定義了豐富而功能強大的擴展點,用戶可以利用這些擴展點,定義和實現(xiàn)各種定制功能。

            首先要搭建擴展開發(fā)環(huán)境,Jazz.net 網(wǎng)站提供了詳細的下載 SDK 鏈接,以及參考文檔。

            RTC Server 端服務(wù)的擴展,有關(guān) Jazz Component 開發(fā)詳細資料請查看參考資源中提供的鏈接。Jazz Component 開發(fā)擴展擴展點"com.ibm.team.repository.common.components",定義服務(wù)類接口,類型是 Raw_HTTP。

            清單 6

          <?xml version="1.0" encoding="UTF-8"?>
          <?eclipse version="3.2"?>
          <plugin>
             <!--
                This extension defines our component to Jazz. Note that the
                common plugin is included on both the client and server, so
                the component is known both places.
             -->
             <extension
                   point="com.ibm.team.repository.common.components">
                <component
                      id="com.ibm.rational.svt.workitem.extensions"
                      name="Workitem Validation Workflow">
                   <service
                         kind="RAW_HTTP"
                         name="Workitem Validation WorkFlow Rest Service" 
                         uri="com.ibm.rational.svt.workitem.extensions.common.
                              IWorkitemValidationWorkflowRestService"
                         version="1">
                   </service>
                </component>
             </extension>
          </plugin>


          posted on 2013-04-12 11:43 順其自然EVO 閱讀(446) 評論(0)  編輯  收藏


          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          <2013年4月>
          31123456
          78910111213
          14151617181920
          21222324252627
          2829301234
          567891011

          導(dǎo)航

          統(tǒng)計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 巨野县| 福建省| 喀喇沁旗| 香港| 赣州市| 焦作市| 三门县| 吉隆县| 双辽市| 合江县| 祁门县| 罗江县| 巫溪县| 咸阳市| 高台县| 塔城市| 苏尼特左旗| 镇安县| 阿拉善右旗| 扎兰屯市| 灌云县| 寿阳县| 富川| 东源县| 清新县| 友谊县| 深州市| 尖扎县| 沅江市| 济阳县| 铁岭县| 惠来县| 响水县| 阿坝县| 柘荣县| 洪雅县| 舒兰市| 鄱阳县| 巩义市| 蕲春县| 景泰县|