HttpRunner 的測試用例分層機制

背景描述

HttpRunner中,測試用例引擎最大的特點就是支持YAML/JSON格式的用例描述形式。git

採用YAML/JSON格式編寫維護測試用例,優點仍是很明顯的:github

  • 相比於表格形式,具備更增強大的靈活性和更豐富的信息承載能力;
  • 相比於代碼形式,減小了沒必要要的編程語言語法重複,並最大化地統一了用例描述形式,提升了用例的可維護性。

以最多見的登陸註銷爲例,咱們的測試用例一般會描述爲以下形式:django

- config:
 name: demo-login-logoff
 variable_binds:
 - UserName: test001
 - Password: 123456
 request:
 base_url: http://xxx.debugtalk.com
 headers:
 Accept: application/json
 User-Agent: iOS/10.3

- test:
 name: Login
 request:
 url: /api/v1/Account/Login
 method: POST
 json:
 UserName: $UserName
 Pwd: $Password
 VerCode: ""
 validators:
 - eq: ["status_code", 200]
 - eq: ["content.IsSuccess", True]
 - eq: ["content.Code", 200]

- test:
 name: Logoff
 request:
 url: /api/v1/Account/LoginOff
 method: GET
 validators:
 - eq: ["status_code", 200]
 - eq: ["content.IsSuccess", True]
 - eq: ["content.Code", 200]
複製代碼

相信你們已經對該種用例描述形式十分熟悉了。不過,該種描述形式的問題在於,接口一般會出如今多個測試場景中,而每次都須要對接口進行定義描述,包括請求的URL、Header、Body、以及預期響應值等,這就會產生大量的重複。編程

例如,在某個項目中存在三個測試場景:json

  • 場景A:註冊新帳號(API_1/2)、登陸新註冊的帳號(API_3/4/5)、查看登陸狀態(API_6);
  • 場景B:登陸已有帳號(API_3/4/5)、註銷登陸(API_7/8);
  • 場景C:註銷登陸(API_7/8)、查看登陸狀態(API_6)、註冊新帳號(API_1/2)。

按照常規的接口測試用例編寫方式,咱們須要建立3個場景文件,而後在各個文件中分別描述三個測試場景相關的接口信息。示意圖以下所示。api

在本例中,接口(API_1/2/6)在場景A和場景C中都進行了定義;接口(API_3/4/5)在場景A和場景B中都進行了定義;接口(API_7/8)在場景B和場景C中都進行了定義。能夠預見,當測試場景增多之後,接口定義描述的維護就會變得很是困難和繁瑣。bash

接口的分層定義描述

那要如何進行優化呢?app

其實也很簡單,在編程語言中,若是出現重複代碼塊,咱們一般會將其封裝爲類或方法,而後在須要時進行調用,以此來消除重複。一樣地,咱們也能夠將項目的API進行統必定義,裏面包含API的請求和預期響應描述,而後在測試場景中進行引用便可。編程語言

示意圖以下所示。模塊化

具體地,咱們能夠約定將項目的全部API接口定義放置在api目錄下,並在api目錄中按照項目的系統模塊來組織接口的定義;同時,將測試場景放置到testcases目錄中。

此時測試用例文件的目錄結構以下所示:

✗ tree tests
tests
├── api
│   └── v1
│       ├── Account.yml
│       ├── BusinessTrip.yml
│       ├── Common.yml
│       └── Leave.yml
├── debugtalk.py
└── testcases
    ├── scenario_A.yml
    ├── scenario_B.yml
    └── scenario_C.yml
複製代碼

而對於API接口的定義,與以前的描述方式基本一致,只作了兩點調整:

  • 接口定義塊(block)的標識爲api
  • 接口定義塊中包含def字段,形式爲api_name(*args),做爲接口的惟一標識ID;須要注意的是,即便api沒有參數,也須要帶上括號,api_name();這和編程語言中定義函數是同樣的。
- api:
 def: api_v1_Account_Login_POST($UserName, $Password)
 request:
 url: /api/v1/Account/Login
 method: POST
 json:
 UserName: $UserName
 Pwd: $Password
 VerCode: ""
 validators:
 - eq: ["status_code", 200]
 - eq: ["content.IsSuccess", True]
 - eq: ["content.Code", 200]

- api:
 def: api_v1_Account_LoginOff_GET()
 request:
 url: /api/v1/Account/LoginOff
 method: GET
 validators:
 - eq: ["status_code", 200]
 - eq: ["content.IsSuccess", True]
 - eq: ["content.Code", 200]
複製代碼

有了接口的定義描述後,咱們編寫測試場景時就能夠直接引用接口定義了。

一樣是背景描述中的登陸註銷場景,測試用例就描述爲變爲以下形式。

- config:
 name: demo
 variable_binds:
 - UserName: test001
 - Password: 123456
 request:
 base_url: http://xxx.debugtalk.com
 headers:
 Accept: application/json
 User-Agent: iOS/10.3

- test:
 name: Login
 api: api_v1_Account_Login_POST($UserName, $Password)

- test:
 name: Logoff
 api: api_v1_Account_LoginOff_GET()
複製代碼

不難看出,對API接口進行分層定義後,咱們在測試用例場景中引用接口定義時,與編程語言裏面調用函數的形式基本徹底同樣,只須要指定接口的名稱,以及所需傳遞的參數值;一樣的,即便沒有參數,也須要帶上括號。

實現接口的分層定義描述後,咱們就能夠避免接口的重複定義。可是,咱們回過頭來看以前的案例,發現仍然會存在必定的重複。

如上圖所示,場景A和場景C都包含了註冊新帳號(API_1/2)和查看登陸狀態(API_6),場景A和場景B都包含了登陸已有帳號(API_3/4/5),場景B和場景C都包含了註銷登陸(API_7/8)。

雖然咱們已經將接口的定義描述抽離出來,避免了重複的定義;可是在實際業務場景中,某些功能(例如登陸、註銷)會在多個場景中重複出現,而該功能又涉及到多個接口的組合調用,這一樣也會出現大量的重複。

接口的模塊化封裝

玩過積木的同窗可能就會想到,咱們也能夠將系統的經常使用功能封裝爲模塊(suite),只須要在模塊中定義一次,而後就能夠在測試場景中重複進行引用,從而避免了模塊功能的重複描述。

具體地,咱們能夠約定將項目的全部模塊定義放置在suite目錄下,並在suite目錄中按照項目的功能來組織模塊的定義。

後續,咱們在testcases目錄中描述測試場景時,就可同時引用接口定義和模塊定義了;模塊和接口的混合調用,必將爲咱們編寫測試場景帶來極大的靈活性。

此時測試用例文件的目錄結構以下所示:

✗ tree tests
tests
├── api
│   └── v1
│       ├── Account.yml
│       ├── BusinessTrip.yml
│       ├── Common.yml
│       └── Leave.yml
├── debugtalk.py
├── suite
│   ├── BusinessTravelApplication
│   │   ├── approve-application.yml
│   │   ├── executive-application.yml
│   │   ├── reject-application.yml
│   │   └── submit-application.yml
│   └── LeaveApplication
│       ├── approve.yml
│       ├── cancel.yml
│       └── submit-application.yml
└── testcases
    ├── scenario_A.yml
    ├── scenario_B.yml
    └── scenario_C.yml
複製代碼

須要注意的是,咱們在組織測試用例描述的文件目錄結構時,遵循約定大於配置的原則:

  • API接口定義必須放置在api目錄下
  • 模塊定義必須放置在suite目錄下
  • 測試場景文件必須放置在testcases目錄下
  • 相關的函數定義放置在debugtalk.py

至此,咱們實現了測試用例的接口-模塊-場景分層,從而完全避免了重複定義描述。

腳手架工具

得益於約定大於配置的原則,在HttpRunner中實現了一個腳手架工具,能夠快速建立項目的目錄結構。該想法來源於Djangodjango-admin.py startproject project_name

使用方式也與Django相似,只須要經過--startproject指定新項目的名稱便可。

$ hrun --startproject helloworld
INFO:root: Start to create new project: /Users/Leo/MyProjects/helloworld
INFO:root:      created folder: /Users/Leo/MyProjects/helloworld
INFO:root:      created folder: /Users/Leo/MyProjects/helloworld/tests
INFO:root:      created folder: /Users/Leo/MyProjects/helloworld/tests/api
INFO:root:      created folder: /Users/Leo/MyProjects/helloworld/tests/suite
INFO:root:      created folder: /Users/Leo/MyProjects/helloworld/tests/testcases
INFO:root:      created file: /Users/Leo/MyProjects/helloworld/tests/debugtalk.py
複製代碼

運行以後,就會在指定的目錄中生成新項目的目錄結構,接下來,咱們就能夠按照測試用例的接口-模塊-場景分層原則往裏面添加用例描述信息了。

總結

若是看到這裏你還不明白測試用例分層的必要性,那也不要緊,測試用例分層不是必須的,你仍是能夠按照以前的方式組織測試用例。不過當你某一天發現須要進行分層管理時,你會發現它就在那裏,很實用。

最後,在HttpRunner項目的examples/HelloWorld目錄中,包含了一份完整的分層測試用例示例,相信會對你們有所幫助。

相關文章
相關標籤/搜索