天天看點

接口自動化測試的一點總結

前言

本文是我在公司總結的一點點個人建議, 可能有非常多的遺漏, 先記錄下來這時候我的了解。公司是做共享單車業務的, 是以場景基本上也可以複用, 畢竟大家都騎過單車。注明: code是我司接口傳回的标志。

編寫之前

  • 接口相關(這塊總結不全)

    了解接口的功能及其使用場景(正常/異常)及接口具體做的事情。

    • 接口實作了什麼功能
    • 接口是否有操作了資料庫對應字段
    • 接口是否有操作了redis對應key
    • 接口的入參

      包括必填項和選填項丢失/多餘帶來的影響, 入參字段的長度是否有限制, 如身份證姓名等

    • 接口的出參

      包括正常/異常場景下code, msg等字段的校驗, 如有傳回資料, 對傳回資料的校驗如何去做

    • 接口的設計是否符合功能的預期

      如資料不允許重複時, 連續調用接口2次是否會插入2條資料

  • 場景準備
    • 掌握每個場景所需要的前置條件

      如關鎖接口在 正常使用時,他的前置條件為該車輛的鎖已經打開。

    • 考慮如何設計場景

      可選擇資料庫/redis添加測試資料或調用接口新增資料的辦法(==接口之間會存在依賴, 一旦添加資料的接口出錯, 此場景也無法驗證==)

  • 用例資料準備
    • 盡可能的動态準備測試資料

      如車輛編号, 可選擇從資料庫撈取。如有身份證号+姓名這種較為複雜的資料, 可寫在變量裡。但需要多挑選幾組資料, 随機讀取

    • 資料依賴

      優先采取新增資料的方式, 保證之前資料完好, 新增資料如有name等字段, 可帶上特定辨別+時間戳的方式。在用例執行完成之後将其清除, 如果出現垃圾資料, 也便于使用定時任務進行清理。

    • 盡量不要把資料寫死
  • 斷言

    對比較重要的字段作斷言, 如需要展示給使用者的字段。

    • http狀态碼校驗
    • code/msg校驗
    • db校驗(業務相關, 如無類似情況可忽略)

      存在接口名傳回與資料庫不一緻的情形, 應以接口為主。db目前多使用下劃線式, 接口出參常使用駝峰式。編寫sql查詢語句的時候, 使用

      select ride_type as rideType

      此類。
    • 異常場景db校驗

      為了防止: 接口出參傳回code不為0, 但db卻被修改。

    • redis校驗

      如有涉及到redis, 需要對redis字段做斷言。

    • 最近比較火的異步接口

      異步接口如何做斷言, 本人沒有太多接觸。由于http協定是無狀态的, 異步接口一般是調用後将任務放入消息隊列, 接口就成功傳回了。我的了解是去檢查消息隊列是否存在消息, 如有如果被消費了, 可起一個收尾類似tearDown的用例專門針對異步接口, 當他們消費完畢之後, 再對資料庫/redis進行相關校驗。

開始編碼

  • 編碼

    gat是公司内部封裝的基于golang的自動化測試架構, 其實隻封裝了http請求和做了一部分單元測試架構的工作。

    • 用例描述

      用例編寫之前, 腦海裡應該有以下幾點。如何設計場景, 覆寫哪些場景, 如何做斷言。可以在檔案頂部, 寫入自己的思路, 這樣在編碼過程中會遊刃有餘, 不至于亂了方寸。之後維護的時候也不至于被業務邏輯繞暈。

    • setUp和tearDown

      目前gat架構是由TestFuncName為入口, 我們可以在函數開始執行後, 調用setUp()函數, 将自己想處理, 想得到的資料都處理完成。再後面就是邏輯的代碼, 到最後使用tearDown進行清理。

    • 用例名稱與Action對應, 檔案名盡量與結構體名一緻
    • 大體結構
    • 注釋要多寫, 常用方法可以封裝
      /*
      測試功能點: 檢查使用者行程
      
      覆寫到的場景:
      1. 使用者正在騎行中
      2. 使用者未騎行
      
      資料準備:
      這裡填寫, 你将怎樣制作資料
      
      資料清理:
      這裡填寫, 你将如何清理髒資料
      
      用例執行流程:
      這裡寫你的執行思路, 首先檢測什麼測試點, 然後....
      
      斷言:
      寫出斷言的标準, 理由, 如何做(這也是評審的一部分)
      
      */
      
      package UserCenter
      
      import (
              "fmt"
              "testing"
              )
      
      type struct UserRideCheck {
          Data []map[string]interface{} // 測試資料
          Action string  //調用接口名
      }
      
      func (u *UserRideCheck) setUp() {
          fmt.Println("用例正準備執行!")
      }
      
      func (u *UserRideCheck) tearDown() {
          fmt.Println("用例執行完畢, 正在清理!")
      }
      
      func (u *UserRideCheck) TestUserRideCheck() {
          setUp()  // 初始化
          //主邏輯, 可再封裝函數
          defer tearDown()  // 清理(後續可添加Recovery防止用例失敗阻塞)
      }
      
      func init() {
          // 自己架構添加用例的邏輯
          data := initStruct()
          testcase.Cases["UserCenter"] = append(testcase.Cases["UserCenter"], data)
      }
      
      func initStruct() *UserRideCheck{
          return &UserRideCheck {
              Action: "user.ride.check"
          }
      }
      
      // unittest
      func UnitTestUserRideCheck(t *testing.T) {
          u := initStruct()
          u.TestUserRideCheck()
      }           

附加:

  • 如果可能的話, 對開發做代碼走查, 盡可能覆寫其if else分支
  • 我們自身的代碼也會出錯, 我們需要用日志記錄測試過程中接口出現的問題以及自己的問題
  • 如果可以, 與CI結合