基於 Htte 的 API 自動化測試

SigodenH發表於2018-04-28

本文將以一款超簡單的部落格應用為例子,介紹如何使用 Htte 進行 API 介面的自動化測試。

Htte 介紹

Htte 是一款自動化測試框架。它允許你使用 YAML 編寫測試,不需要編寫程式碼。 難度低,上手快。

編寫一個測試就是羅列出請求資料以及預期的響應資料。htte 會自動為你生成請求,並驗證響應資料是否匹配預期。

它提供外掛,沒有什麼資料是生成和表示不了的,沒有什麼資料是無法校驗和比對的,沒有什麼場景是測試不了。

介面自動化測試中,測試中使用來自其它測試的資料一直是難言的痛。Postman 通過環境變數處理這個問題,繁瑣又容易出錯,Htte 創新獨到 地採用會話和路徑引用資料處理這個問題,安全而簡便。

Htte 是一款優秀的介面自動化測試工具,值得大家一試。

安裝

使用 npm 安裝 htte 命令列:

npm i -g htte
複製程式碼

介面詳情

有這樣一款超簡單的部落格應用。它只有四個介面。

  • 登入介面
功能: 使用者登入
請求路徑: localhost:3000/login
請求方法: POST
請求頭: { "Content-Type": "application/json" }
請求資料: {"username": "john", "password": "johnsblog"}
響應:
  - 狀況: 使用者名稱和密碼正確
    響應狀態碼: 200
    響應資料: {"name": "john", "token": "..."}
  - 狀況: 使用者名稱或密碼不正確
    響應狀態碼: 401
    響應資料: {"errcode": 11001, "message": "invalid username or password"}
複製程式碼
  • 新增博文
功能: 新增博文
請求路徑: localhost:3000/articles
請求方法: POST
請求頭: { "Content-Type": "application/json", "Authorization": "Bearer ..." }
請求資料: >
  {
    "title": "How to use htte",
    "content": "htte is ....",
    "tags": ["howto", "htte"]
  }
響應:
  - 狀況: 新增成功
    響應狀態碼: 200
    響應資料: >
      {
        "title": "How to use htte",
        "slug": "how-to-use-htte-A43bcF",
        "content": "htte is ....",
        "tags": ["howto", "htte"],
        "createdAt": "2018-04-28T07:35:08.471Z"
      }
複製程式碼
  • 編輯博文
功能: 編輯博文
請求路徑: localhost:3000/article/how-to-use-htte-A43b
請求方法: PUT
請求頭: { "Content-Type": "application/json", "Authorization": "Bearer ..." }
請求資料: >
  {
    "title": "How to create htte plugin",
    "content": "htte plugin is ....",
    "tags": ["howto", "htte", "plugin"]
  }
響應:
  - 狀況: 編輯成功
    響應狀態碼: 200
    響應資料: >
      {
        "title": "How to use htte plugin",
        "slug": "how-to-use-htte-A43b",
        "content": "htte plugin is ....",
        "tags": ["howto", "htte", "plugin"],
        "createdAt": "2018-04-28T07:35:08.471Z"
      }
複製程式碼
  • 獲取博文列表
功能: 獲取所有博文
請求路徑: localhost:3000/articles
請求方法: GET
請求頭: { "Content-Type": "application/json", "Authorization": "Bearer ..." }
querystring: tag=howto
響應:
  - 狀況: 成功
    響應狀態碼: 200
    響應資料: 
      {
        "articlesCount": 1,
        "articles": [
          {
            "title": "How to use htte plugin",
            "slug": "how-to-use-htte-A43b",
            "content": "htte plugin is ....",
            "tags": ["howto", "htte", "plugin"],
            "createdAt": "2018-04-28T07:35:08.471Z"
          }
        ]
      }
複製程式碼

測試介面

新增配置檔案 .htte.yaml,描述介面

url: http://localhost:3000
type: json # 使用 json 解壓縮請求響應資料
apis:
  login:
    method: post
    uri: /login
  createArticle:
    method: post
    uri: /articles
  updateArticle:
    method: put
    uri: /article/{slug}
  listArticles: /articles
複製程式碼

新增測試檔案 blog.yaml,編寫測試。

測試登入失敗

units:
  - describe: 登入失敗
    api: login
    req:
      body:
        username: john
        password: johnblog
    res:
      status: 401
      body:
        errcode: 11001
        message: !@exist
複製程式碼

describe 描述測試的目的,該欄位會在最好的測試報告中呈現。

api 描述被測試的介面,該欄位關聯配置檔案中的介面定義。

req 定義請求資料, body下的資料會封裝到請求體 {"username": "john", "password": "johnblog"}

res 期望響應資料。如果與實際響應資料不匹配,會導致測試不通過。

當 htte 載入這段測試程式碼,會構造請求,也就是會往 http://localhost:3000/login 傳送 post 請求, 有請求頭 {"Content-Type": "application/json"}, 及請求體 {"username": "john", "password": "johnblog"}。 當服務端響應後,會對響應的資料作如下斷言

  • 響應狀態碼為 401
  • 響應體是一個物件
  • 響應體物件有且僅有兩個屬性 errcodemessage
  • 響應體物件的 errcode 屬性值為 11001
  • 響應體物件的 message 屬性值為 invalid username or password

所以斷言全部通過,測試才會通過。如響應狀態碼不為 401 或者響應體中多了其它其它欄位,都是不完全匹配,會導致測試失敗。

測試登入成功

  - describe: 登入成功
    api: login
    name: johnLogin
    req:
      body:
        username: john
        password: johnsblog
    res:
      body:
        username: john
        token: !@exist
複製程式碼

name 定義測試名稱,後續測試可以通過該名稱訪問該 測試資料,比如響應的 token 值。

res 中省略了 status,並不代表不檢查狀態碼了。對於這種情況 htte 會檢查是否狀態碼在 200-299 範圍內。

token 的值是變動的,我們檢查其具體值。所以使用 YAML 標籤 !@exist 進行一種特殊的檢查。其驗證 token 欄位存在,不校驗其具體值。

!@exist 由 htte 外掛提供。在只關注欄位有無而不在意值的情況下使用。

測試新增博文

  - describe: 新增博文成功
    api: createArticle
    name: articleUsehtte
    req:
      headers: 
        Authorization: !$concat ['Bearer', ' ', !$query $$johnLogin.res.body.token]
      body:
        title: How to use htte
        content: htte is http automation testing tool
        tags: 
          - howto
          - htte
    res:
      body:
        title: How to use htte
        slug: !@regexp /^how-to-use-htte/
        content: htte is http automation testing tool
        tags: 
          - howto
          - htte
        createdAt: !@exist
複製程式碼

headers 描述請求頭。它將向傳送的請求頭中追加 Authorization 頭。

新增博文介面會進行 JWT 許可權校驗,因此我們需要新增 Authorization 頭,提供登入 token

這個 token 可以從測試 johnLogin 中獲取。我們通過標籤 !$query 引用這個 token 值。

htte 會通過會話記錄執行過的測試的請求和響應資料,你可以這種方式獲取位於你前面的測試的資料。不需要預先定義,只需要定位(訪問路徑)。

然後使用標籤 !$concat 拼接 Bearertoken 值得到 Authorization 的具體值。

slug 表示博文的訪問連結,通過 title 拼接一個 4 個字元的隨機字串生成。它也不是一個具體值,所以我們使用 !@regexp 進行正這而匹配驗證。

大多情況下,測試的請求資料及預期響應資料是可以給定的,但總免不了會碰到一些特殊狀況,這是就需要使用外掛了。htte 許多內建外掛,它們 應該足夠應對絕大多數常見了。如果碰到無法處理的情況,可以發 issue 或編寫外掛。

測試編輯博文

  - describe: 編輯博文成功
    api: updateArticle
    req:
      headers: 
        Authorization: !$concat ['Bearer', ' ', !$query $$johnLogin.res.body.token]
      params:
        slug: !$query $$articleUsehtte.res.body.slug
    res:
      body:
        title: How to use htte plugin
        slug: !@query $$$req.params.slug
        content: htte plugin is flexiabe
        tags: 
         - howto
         - htte
         - plugin
        createdAt: 2018-04-28T07:35:08.471Z
複製程式碼

params 描述路徑引數,該測試的請求路徑是 /article/{slug},帶有路徑引數 slug, 傳送請求前 htte 會將替換成 params 中對應的值,最終的請求路徑是 /article/how-to-use-htte-A43bcF

!@query 標籤檢驗響應值是否某個引用值相等,用來判斷更新文章或 slug 是否改變。

測試獲取博文列表

獲取我的所有博文

  - describe: 獲取我的所有博文
    api: listArticles
    req:
      headers: 
        Authorization: !$concat ['Bearer', ' ', !$query $$johnLogin.res.body.token]
    res:
      body:
        articlesCount: !@exist
        articles: !@array
          0: 
            title: How to use htte plugin
            slug: !@regexp /^how-to-use-htte/
            content: htte plugin is flexiabe
            tags: 
              - howto
              - htte
              - plugin
            createdAt: !@exist
複製程式碼

!@array 要特別注意。Htte 常規狀態下比對陣列時,會先比對元素個數,在逐一比對個元素。 而 articles 可能是一個長度不固定的陣列,,這種狀況下進行常規比對沒有意義。 使用 !@array 自定義陣列比對行為,使其僅比對特定的元素,比如該測試中,就表示僅對第一個元素進行比對,忽略其它元素。 如果該元素匹配,則測試通過。

通過標籤賽選我的博文

  - describe: 通過標籤篩選我的博文
    api: listArticles
    req:
      headers: 
        Authorization: !$concat ['Bearer', ' ', !$query $$johnLogin.res.body.token]
      query:
        tag: howto
    res:
      body:
        articlesCount: !@exist
        articles: !@array
          0: 
            title: How to use htte plugin
            slug: !@regexp /^how-to-use-htte/
            content: htte plugin is flexiabe
            tags: 
              - howto
              - htte
              - plugin
            createdAt: !@exist
複製程式碼

query 描述 querystring, 測時的 url 將變成 http://localhost:3000/articles?tag=howto

命令列

保證 Web 可用的情況下,在檔案 .htte.yamlblog.yaml 所在的目錄,執行命令 htte, htte 會逐一執行測試。 並列印測試執行的結果。

一些 htte 命令列有些實用技巧:

  • 某個測試失敗時暫停執行
htte --bail 
複製程式碼
  • 從上次失敗的地方開始執行, 適合介面除錯
htte --bail --amend
複製程式碼
  • 僅執行指定測試
htte --unit blog-articleUsehtte --shot
複製程式碼
  • 顯示除錯資訊,將同步列印請求響應資料
htte --debug
複製程式碼

結論

通過這個僅僅 4 介面的部落格應用介面測試案例,你應該很很熟悉 Htte 了,就是這麼簡單。 Htte 自動生成資料,傳送請求,比對響應資料,編排測試用例並逐一執行,列印報告。

所謂測試就是使用 YAML 描述介面的請求和響應。對於描述不了的極少部分場景提供了外掛。 即享有描述性策略編寫測試的優越性,又持有外掛帶來的靈活性。

專案地址: github.com/sigoden/htt…

相關文章