我對自動化測試的一些認識

前言

從2017年初開始,到如今差很少半年多的時間,我這邊投入了一部分精力用於項目的自動化測試建設工做。目前來看收益仍是比較明顯的,在這個過程當中也加深了對自動化測試的理解,這邊就總結下本身對自動化測試的認識。html

首先我想說下在開展自動化先後,個人工做情況的對比:前端

  • 去年2016年Q三、Q4,基本上每天處於996甚至997的狀態。大部分時間都花在了功能測試保障、迴歸測試和上線驗證。由於項目在線上有多達7,8個不一樣的集羣,每一次版本上線爲了保險起見,開發會一個集羣一個集羣當心翼翼地上線,因此基本上每天都處於上線的狀態。每次上線,手工測試時間順利的話在半小時左右,若是遇到問題跟開發聯調定位,會達到數個小時。除了時間上開銷很大以外,每次上線帶來的精神上的壓力其實更嚴重,很是懼怕哪一個用戶半夜跳出來反饋說調度有Bug。java

  • 在開展了自動化測試以後,如今我給「平常版本迭代測試」只預估了25%的工做量。任意集羣上線,我只要負責點一下Jenkins的「開始構建」按鈕,便可完成驗收。若是有出現用例失敗,會自動發送郵件告知開發。web

顯然,目前的工做狀態要好不少,是由於項目工做量減小了嗎?顯然不是。其實今年以來整個項目組在研發的投入要比去年更多,工做量只會比之前更重,還要兼顧多個私有化部署的客戶的驗收和平常測試保障工做,工做量確定是只增不減的。之因此能有更多的時間空餘出來作其它更多維度的事情,這一切都得益於「自動化測試」的幫助,它極大地解放了個人手工測試時間,同時更加提高了上線的信心。sql

1. 需求和目標

在我開展自動化測試以前,其實該項目之前的測試人員也已經寫了不少的接口測試用例,可是大多數用例處於「半癱瘓」狀態,在CI上無人維護(據說起初是有人維護的,可是後來用例多了,維護的人每次花很長時間去定位問題,結果卻發現大部分的問題都是環境問題致使,花了半天時間定位卻沒什麼收益,長此以往便不想去維護)。看起來,自動化彷佛並無什麼收益,反而維護用例會形成額外的工做負擔。docker

我以爲,其實自動化測試跟其它任何一種測試類型(好比異常測試、穩定性測試、性能測試等)都是相似的,它也是一種測試類型而已。在開展測試以前,咱們首先必需要明確自動化測試的需求是什麼,要解決什麼樣的問題。shell

1.1 讓「自動化」代替「手動」

在我看來,初期的自動化測試,個人目標很明確,我就是要讓「自動化」代替「手動」,讓自動化真正地跑起來,凡是「自動化」跑過的內容,我毫不再去手工重複執行一遍。這樣至少我有一個很明確的收益:每完成一條自動化用例,我減小了一條手工用例的執行時間。數據庫

必需要提醒的是,讓「自動化」徹底替代「手動」,其實對自動化用例的穩定性、容錯都有必定的要求。你要花必定時間去思考用例執行過程當中的異常場景,是否足以充分替代手工測試。所以,我在增長用例的時候都會很是謹慎,確保用例集是穩定100%經過的前提下才會增長新的用例。apache

對於正常狀況下(排除環境、開發代碼的問題)有時100%經過,有時90%經過的自動化用例集,我以爲它的做用和參考價值爲0。正常的用例集就應該是100%經過的。編程

1.2 讓「迴歸」自動化

上節說了讓「自動化」替代「手動」,每完成一條自動化用例都是有明顯收益的。那如何讓收益最大化呢,固然是讓每次迴歸或上線驗證「不得不」執行的用例優先自動化。若是完成了迴歸用例集的所有自動化,那我就能夠用它來替代個人平常回歸,和上線迴歸工做,極大地釋放個人手工驗證時間。

這裏必需要指出的是,我跟的項目實際上是一個對系統穩定性的要求要高於新功能的引入的一個後臺項目,因此它的核心功能是比較固定的,其實大多數後臺項目也是相似的,核心功能聚合、對系統的穩定性要求高。這就須要保障系統的核心功能完善。因此咱們能夠先將「核心功能」的驗證完成自動化。

1.3 不要讓環境成爲瓶頸

前面說了,舊的用例集在維護的過程當中給測試人員增長了不少額外的負擔,到最後發現不少都是環境的問題。當時的情形就是專門搭建了另外一套測試環境專門用於自動化測試,而大數據的後臺環境搭建和維護很是的複雜,若是同時維護多套環境,不免會在一些組件升級的過程當中出現遺漏,致使環境不一樣步。所以,咱們的自動化測試用例前期徹底能夠直接在功能測試環境執行,由於功能測試環境確定是會一直隨着版本的迭代向前不斷更新的。

2. 技術選型

在明確了目標後,要開始技術選型。常見的自動化測試類型,包括

  • 接口自動化
  • UI自動化
  • 基於shell交互命令執行的自動化

此外,不屬於測試範疇,可是也能夠實現自動化、釋放手工時間的還有

  • 數據準備自動化
  • 環境編譯、部署、打包自動化
  • 穩定性測試/性能測試結果指標獲取、校驗自動化
  • 機器資源監控、報警自動化
  • 其它全部手工重複執行的操做

在開始自動化以前,首先要分析項目的架構和情況。對於一個後端的服務,它若是是純粹以接口的形式提供給其它組件去調用,那能夠採起「接口自動化」;對於一個Web產品,若是先後端都在測試的保障範圍,並且前端頁面相對比較穩定,能夠考慮採用「UI自動化」(此時接口自動化其實已經不足以保障產品的端到端功能);對於更後端的組件,若是想測試組件自身的基礎核心功能,能夠採用「基於shell交互命令執行的自動化」,經過自動化腳本的方式封裝shell命令的調用。

此外,有些人可能還會執着於編程語言的選擇,是用Java仍是Python仍是Shell,或者其它語言等等。這個我以爲其實沒有定論,能夠根據本身對語言的偏好和熟練程度,可是必需要考慮團隊成員的廣泛技術棧,由於後期可能其餘人來接手這個項目時須要代替你去維護測試工程。一般來講,測試框架的選擇(無論是接口自動化、UI自動化)推薦使用Java的TestNG框架;對於簡單的基於命令行執行的自動化腳本的編寫推薦使用Shell(Shell很是地強大);對於稍複雜的一些自動化的腳本的編寫,推薦使用Python,在Python中能夠很是方便地封裝Shell命令,同時Python區別於Shell的一個特性就是它支持面向對象的封裝,能夠將一些對象封裝在特定的類中,增長程序的可讀性和健壯性。

這裏再插一段題外話:有些人可能會疑惑,如今其實有不少接口測試平臺,測試人員能夠直接在平臺上完成接口測試,在選型時怎麼抉擇?——這裏我不評價哪一種方式更好,只想說下本身的見解:我以爲兩種其實各有各的好處:

  • 編寫代碼的方式:

優勢:提高本身的編碼能力,問題定位能力,具有更高的靈活性和可操做性。 缺點:結果展現不直觀,不易於協做。其餘人維護代碼困難,難以推進開發執行。

  • 接口平臺的方式:

優勢:簡便,上手容易,能夠在項目組間很好的協做和維護,測試記錄和結果一目瞭然。 缺點:離開了平臺,可能又要回歸手動。

對於測試人員而言,若是有精力和時間的話,我建議是兩種都要掌握,甚至是本身去開發接口測試平臺的能力。

3. 自動化實施過程

目前我跟的項目裏已經實現自動化的內容包括:基於接口的場景迴歸自動化測試、編譯部署過程自動化、Jacoco覆蓋率統計並接入CR平臺(代碼變動分析平臺)的自動化、對外/上線打包發佈的自動化、穩定性測試結果校驗的自動化。

下面着重介紹下項目的接口自動化框架的搭建和設計過程。

3.1 準備工做

老生常談,開始自動化前,我仍然想再次強調必定要明確本身的需求是什麼。在個人項目裏,個人需求主要有如下幾點:

  • 同一份代碼能夠在多個集羣執行
  • 各個集羣的測試數據相互獨立,不會互相影響
  • 能夠方便地與數據庫進行交互
  • 當用例執行出錯時,有詳細的日誌幫助定位
  • 較好的可維護性和集羣擴展性。

3.2 框架搭建

3.2.1 環境搭建

環境搭建時,主要用瞭如下工具:

  • Git:管理代碼工程
  • TestNG:做爲測試框架
  • Maven:管理依賴包
  • Log4j:管理日誌
  • Hibernate:實現數據庫交互
  • HttpClient:實現請求發送

之因此沒有用MyBatis,以爲相對來講,MyBatis是一個半ORM的框架,它須要本身額外維護一份sql映射文件,而Hibernate是全ORM的,能夠省去這一步。關於它倆的比較,你們能夠參考下知乎的一篇文章:MyBatis和Hibernate的對比。對於JDBC的方式,固然它也能夠訪問數據庫,只不過相對來講,使用ORM框架能夠更貼近面向對象的編程方式。

3.2.2 不一樣集羣配置管理

在實現過程當中,由於不一樣的集羣會有不一樣的配置,好比webserver host、登錄後臺webserver的用戶名/密碼、公共帳號信息、數據庫信息等等。爲了讓一份代碼能夠在不一樣集羣去共用,就必須把這些配置信息從代碼中剝離出來。能夠用配置文件的形式來統一管理集羣的配置信息,如圖所示:

配置文件管理

每一個文件表明一個集羣的配置。在代碼中能夠經過java.util.Properties類讀取配置文件的方式載入各項配置信息:

/**
 * 根據指定的配置文件名,初始化配置
 * @param configFile
 * @throws IOException
 */
public PropertiesUtil(String configFile) throws IOException{
    this.configFile =DEFAUL_CONFIG_FILE_DIRECTORY + configFile;
    InputStream fis = new FileInputStream(this.configFile);
    props = new Properties();
    props.load(fis);
    //關閉資源
    fis.close();
}

/**
 * 根據key值讀取配置的值
 * @param key key值
 * @return key 鍵對應的值 
 * @throws IOException 
 */
public String readValue(String key){
    return  props.getProperty(key);
}

/**
 * 讀取properties的所有信息
 * @throws FileNotFoundException 配置文件沒有找到
 * @throws IOException 關閉資源文件,或者加載配置文件錯誤
 * 
 */
public Map<String,String> readAllProperties(){
    //保存全部的鍵值
    Map<String,String> map=new HashMap<String,String>();
    Enumeration<?> en = props.propertyNames();
    while (en.hasMoreElements()) {
        String key = (String) en.nextElement();
        String property = props.getProperty(key);
        map.put(key, property);
    }
    return map;
}

到這裏,解決了配置讀取的問題,還須要解決代碼運行時如何讓它本身去選擇正確的集羣配置文件的問題。我是將選擇配置文件的邏輯所有封裝到了一個工廠類BaseConfigFactory.java中,在實際測試使用時,我只須要經過工廠類的靜態方法BaseConfigFactory.getInstance()去獲取想要的配置信息,而不須要關心它究竟是如何去選擇正確的配置文件的。工廠類的實現能夠參考:

public class BaseConfigFactory {
    private static final String testEnv= System.getenv("TEST_ENV") == null ? "null" : System.getenv("TEST_ENV");
    private static Logger logger = Logger.getLogger(BaseConfigFactory.class);
    private static BaseConfig baseConfig;
    private static HashMap<String, String> clusterConfigMap;
    public static synchronized BaseConfig getInstance(){
        if (null == baseConfig){
            PropertyConfigurator.configure("log4j.properties");
            initMap();
            setupConfig();
        }
        return baseConfig;
    }
    
    
    public static void initMap(){
        clusterConfigMap = new HashMap<>();
        clusterConfigMap.put("TEST-BJ", "test-bj.properties");
        clusterConfigMap.put("ONLINE-BJ", "online-bj.properties");
        clusterConfigMap.put("ONLINE-XS", "online-xs.properties");
        clusterConfigMap.put("ONLINE-LT", "online-lt.properties");
        clusterConfigMap.put("ONLINE-BEIJING", "online-beijing.properties");
        clusterConfigMap.put("ONLINE-HD", "online-hd.properties");
        clusterConfigMap.put("null", "test-local.properties");
    }
    
    public static void setupConfig(){
        logger.info("TEST ENV: " + testEnv);
        String propertyFile = clusterConfigMap.get(testEnv);
        logger.info("Using '" + propertyFile + "' as property file.");
        baseConfig = new BaseConfig(propertyFile);      
    }

}

即,將全部的集羣的配置放入到一個Map中,而後經過讀取環境變量TEST_ENV的值來選取具體的集羣配置文件clusterConfigMap.get(testEnv)。

3.2.3 log4j日誌管理

良好的日誌輸出是幫助定位問題的關鍵環節,尤爲是定位服務器上執行時出現的問題。這邊貼一個log4j的配置:

### set log levels ###
log4j.rootLogger = debug, stdout, D, E

### 輸出到控制檯 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender 
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy/MM/dd HH:mm:ss.SSS Z} %p [%c{1}] [Thread-%t] %m%n

### 輸出到日誌文件 ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = logs/console.log
log4j.appender.D.Append = true
##輸出Debug級別以上的日誌##
log4j.appender.D.Threshold = INFO  
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern=%d{yyyy/MM/dd HH:mm:ss.SSS Z} %p [%c{1}] [Thread-%t] %m%n

### 保存異常信息到單獨文件 ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
##異常日誌文件名##
log4j.appender.E.File = logs/error.log
log4j.appender.E.Append = true
##只輸出ERROR級別以上的日誌##
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern=%d{yyyy/MM/dd HH:mm:ss.SSS Z} %p [%c{1}] [Thread-%t] %m%n

##Hibernate日誌級別設置
log4j.logger.org.hibernate.ps.PreparedStatementCache=WARN
log4j.logger.org.hibernate=ERROR

# Changing the log level to DEBUG will result in Hibernate generated
# SQL to be logged.
log4j.logger.org.hibernate.SQL=ERROR

# Changing the log level to DEBUG will result in the PreparedStatement
# bound variable values to be logged.
log4j.logger.org.hibernate.type=ERROR

該配置將INFO級別和ERROR級別的日誌分別定位輸出到不一樣的文件,且日誌文件會按照日期進行自動歸檔,輸出的格式包含了日誌的日期、級別、類信息、線程信息、日誌內容等。

通常狀況下,對於接口測試,當接口測試用例失敗時,咱們要打印的日誌包括:請求的url、參數、方法、實際響應、指望響應等等。

3.3 分層設計、解耦

首先看一下項目的工程目錄:

項目工程目錄

能夠看到,項目中包含了多個package,各個package的做用已經在圖片中標示了。之前好多測試人員的習慣是將api代碼的調用、測試方法的編寫、data Provider的編寫、測試數據的構造所有寫在一個類文件中,這樣作其實會有幾個問題:

  • 可讀性差
  • 代碼複用性低
  • 維護性差
  • 難以調試
  • 耦合帶來的其它各種問題

此外,若是不一樣集羣的測試數據不一樣,會有大量的if判斷,結果是災難性的。

下面以一個用例爲例,展現代碼的結構:

測試api:

public class ScheduleApi extends BaseAzkabanApi{
    ...
    ...
    /**
     * 使用默認公共帳號、email、失敗策略、sla報警郵箱新增正常調度。
     * @param projectName
     * @param flow
     * @param projectId
     * @param scheduleTime
     * @param scheduleDate
     * @param period
     * @return
     */
    public ResponseCode addNormSched(String projectName, String flow, String projectId, String scheduleTime, String scheduleDate,String period){
        return scheduleFlow(projectName, flow, projectId, scheduleTime, scheduleDate, defaultProxyUser, defaultProxyEmail, period,  defaultSlaEmail);
    }
    ...
    ...
}

測試代碼test:

@Test(singleThreaded=true)
public class ScheduleTest{
    ...
    ...
    /**
     * 新增正常調度
     * @param projectName
     * @param flow
     */
    @Test(priority=1, dataProvider="addNormSched", dataProviderClass=ScheduleDataProvider.class, testName="1410356")
    public void addNormSched(String projectName, String flow, String expectedStatus, String hasScheduleId, String message){
        ResponseCode rc= scheduleApi.addNormSched(projectName, flow);
        Assert.assertEquals(rc.getStatus(), expectedStatus, message+rc.getDebugInfo("返回結果中的狀態status對應值"));
        Assert.assertEquals(rc.hasProperty("scheduleId"), Boolean.parseBoolean(hasScheduleId), message+rc.getDebugInfo("返回結果中是否包含scheduleId"));
    }
    ...
    ...
}

測試用例dataProvider:

public class ScheduleDataProvider {
    @DataProvider(name = "addNormSched", parallel=true)
    public static Object [][] addNormSched(){
        return new Object[][]{
            ScheduleTestData.validNormSchedule,
            ScheduleTestData.notExistedProject,
            ScheduleTestData.notExistedFlow
        };
    }
    ...
    ...
}

測試數據testdata:

public class ScheduleTestData extends BaseTestData{ 
    ...
    ... 
    //Testdata for addNormSched
    public static Object[] validNormSchedule={VALID_PROJECT_NAME, VALID_NORMAL_SCHEDULE_FLOW, "success", "true", "設置有效的正常調度"};
    public static Object[] notExistedProject={NOT_EXIST_PROJECT_NAME, VALID_NORMAL_SCHEDULE_FLOW, "error", "false", "不存在的project"};
    public static Object[] notExistedFlow={VALID_PROJECT_NAME, NOT_EXIST_FLOW_NAME, "error", "fasle", "不存在的flow"};
    ...
    ...
}

能夠看到,用例的測試代碼test類是很是簡潔的,只要調用api類封裝的接口,而後進行assert判斷便可。

關於測試數據,將dataprovider與testdata進行分離,也是爲了後續可能會靈活地調整下架用例,只須要去除dataprovider類中的用例行便可,而testdata中的數據仍然能夠留着複用。

另外,前面提到了不一樣集羣測試數據的管理。再介紹下我這邊的實現方式:

  • 不一樣測試類使用的公共數據,存放於BaseTestData基類中,讓其它testdata類繼承於基類
  • 不一樣集羣能夠共用的數據,儘可能共用,以常量的方式存儲於testdata類中
  • 不一樣集羣沒法共用的數據,統一存放於特定的json文件管理

關於json文件管理數據,其實跟配置文件的管理相似,以下圖所示:

json數據目錄

History.json:

{           
    "validTotalFetch":{
        "key":"",
        "beginTime":"2017-06-30%2015:30",
        "endTime":"2017-06-30%2015:50",
        "expectedTotal":"7"
    },
    
    "validImmediatelyFetch":{
        "key":"instant_execute_job",
        "beginTime":"2017-06-30%2013:30",
        "endTime":"2017-06-30%2013:40",
        "expectedTotal":"1"
    },
    
    "validScheduledFetch":{
        "key":"online_schedule_job",
        "beginTime":"2017-06-30%2014:30",
        "endTime":"2017-06-30%2014:40",
        "expectedTotal":"2"
    }
}

3.4 改進與提高

在自動化的實施過程當中,還遇到了一些問題可能對其它項目也會有必定的借鑑意義。這邊羅列下幾個我以爲比較有意思的問題。

3.4.1 webserver高可用的支持

咱們的後臺webserver是支持高可用的,因此每次運維上線後webserver的host可能會發生變化,以及在服務運行過程當中也可能會發生webserver切換。若是每次去手動調整自動化用例的配置信息,是一件很是麻煩的事情。

解決的方式就是在配置文件中,將主從webserver的host都填寫進去,在測試過程當中,若是發生請求失敗,則容許切換一次host。

3.4.2 用例併發執行

因爲咱們的一部分用例是異步的場景用例,須要執行一個數據開發的任務,而後等待其執行完成。這些用例的執行比較費時,若是順序執行的話會消耗很是多的時間。所以能夠經過併發執行測試的方式,解決用例耗時的問題。關於TestNG的併發能夠參考這篇文章:《簡單聊聊TestNG中的併發

3.4.3 單例模式解決session問題和host重複切換問題

  • 問題1: Azkaban的每一個接口,都須要一個必傳參數seesion。這個session能夠經過/login接口獲取。若是每一個接口在執行的時候都去調用一次/login接口從新獲取session,就會顯得很冗餘,也可能致使舊的session失效。

  • 問題2: 上述提到的對webserver高可用的支持,當多條用例並行執行時若是同時去切換host,可能會形成host切換回原來的不可用host。

對於問題1,能夠將session做爲單例的方式進行存儲。

對於問題2,能夠借鑑單例模式的「雙重檢查」思想,對切換host的代碼進行部分同步,在防止host重複切換的同時,不會下降httpclient請求的併發性。關於單例模式的應用能夠參考這篇KS文章:《「單例模式」學習及其在優化接口自動化測試代碼中的實踐

3.4.4 「變」與「不變」

其實這也是全部設計模式的基本思想,即區分自動化測試中的「可變因素」和「不變因素」。我以爲ycwdaaaa大神(飛哥)有兩句話是很是棒的:

  • 封裝"一切"可能的可控的變化因素
  • 爲了穩定使盡"一切"手段

4. 結合研發過程的應用

上面介紹了一些自動化的實施過程,這邊再介紹下實施以後在項目研發過程當中的應用。

目前在項目中,主要有如下幾方面的應用。

(1)提測後的自動化迴歸驗收

下圖是項目的一條持續集成pipeline。在開發提測後,我會自動化地完成如下事情:

  • 編譯代碼
  • 將服務部署到各個機器,並完成Jacocod Agent的部署
  • 執行靜態代碼檢查
  • 執行接口測試
  • 完成覆蓋率統計
  • 將覆蓋率統計數據接入到CR平臺

當自動化用例所有執行經過時,說明系統的核心功能迴歸沒有問題,而後開始版本的細粒度功能的測試。

持續集成pipeline

(2)Bug修復後的迴歸驗收

在測試過程當中,開發確定會常常修復bug從新提交代碼,每次有代碼從新提交時,我均可以一鍵完成部署、測試、覆蓋率統計。

(3)上線後的迴歸驗證

目前,項目的上線驗證已經徹底由自動化驗證來替代。

(4)做爲開發冒煙的一部分(未完成)

目前已經跟開發達成一致,開發很是歡迎將自動化用例接入到開發環境,用於他們每次變動時的環境正確性驗證,能夠儘早幫助他們發現研發過程當中出現的問題。而且在提測前,只有100%經過自動化測試才能夠進行提測。

(5)線上監控

目前各個線上集羣,都部署了自動化測試用例,這部分用例會每隔4小時執行一次。用於確保線上環境的穩定性。從效果上來看,線上監控的成效是很是明顯的,提早發現了不少集羣的延遲問題,環境問題等,讓開發能夠及時地收到報警,瞭解線上集羣的狀況。

(6)關於持續集成

可能有人會發現,上述的執行過程其實不是真正意義上的持續集成,真正意義上的持續集成應該是:每次開發提交代碼,自動觸發構建。

必需要認可的是,確實是如此。可是無論怎麼樣,我以爲能夠先從優化測試工做量的角度慢慢去推開整個流程,其實業界目前也並無確切的定論說只有持續集成纔是最佳的實踐。相反,一味地持續集成可能會增長咱們的維護成本。只要咱們能切實提高本身的工做效率,達到目的就能夠了。

5. 成效

當自動化作的比較完善後,你真的會發現:生活原來能夠變得如此簡單美好。

自動編譯部署:測試過程當中開發修復bug提交代碼是很是頻繁的,每次的手動編譯部署可能都會耗費十幾分鍾,而且測試人員的關注點還不能離開。

自動打包發佈:從這個版本開始,全部集羣的上線都會統一使用QA發佈的包。這樣減小了之前每次上線時,開發運維人員要花費大量的時間逐一去拉取各個集羣的代碼再進行編譯、部署。一鍵的打包發佈,能夠在上線前就提早準備好各個集羣的上線包,開發只需調用部署腳本去獲取這些包,而後替換就能夠完成上線。此外,自動打包發佈的方式極大減小了運維上線時漏操做的風險。

自動化迴歸測試:之前一次迴歸測試,須要QA持續地投入超過30分鐘。如今經過一鍵執行,程序會自動地執行,時間控制在5分鐘之內。且QA能夠將注意力放到其它事情上。

自動化完成穩定性測試結果的校驗:從前執行完穩定性測試,須要對着數據庫的一大片數據進行人肉地校驗。會耗費一個下午大半天的時間,甚至仍是有遺漏。經過腳本自動校驗,1分鐘內就能夠出結果報告。

這裏再提一下UI自動化。不少人會對UI自動化有見解,以爲投入產出比不明顯、維護成本高。我認爲UI自動化跟接口自動化其實沒有區別,都是功能迴歸的一種形式而已,選擇哪一種自動化的類型應該取決於項目的實際狀況須要。另外,UI自動化的維護成本目前一個季度作下來看,真的沒有比接口自動化要高,關鍵還在於自動化的設計上是否是作的易於維護。

6. 展望

能夠看到以上的自動化都是基於環境的穩定可用爲前提的。之因此沒有獨立分配一套環境用於自動化測試,也是由於環境維護的成本較高。可是,基於測試人員的增長,測試類型的豐富(異常、性能),在一套環境上執行全部測試顯然會出現相互影響的問題。所以,若是能將測試環境搭建docker化,經過維護docker鏡像的方式,自動化地使用docker鏡像快捷地部署一套新的完整測試環境能夠極大地提升咱們的測試效率。

最後的最後,發自真心地但願圈中的前輩大神能給予我一些參考意見和指導,指出個人不足之處。謝謝!

相關文章
相關標籤/搜索