Files
httprunner/docs/prepare/testcase-layer.md
2019-11-01 23:28:50 +08:00

273 lines
10 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## 测试用例分层模型
在自动化测试领域,自动化测试用例的可维护性是极其重要的因素,直接关系到自动化测试能否持续有效地在项目中开展。
概括来说,测试用例分层机制的核心是将接口定义、测试步骤、测试用例、测试场景进行分离,单独进行描述和维护,从而尽可能地减少自动化测试用例的维护成本。
逻辑关系图如下所示:
![](../images/testcase-layer.png)
同时,强调如下几点核心概念:
- 测试用例testcase应该是完整且独立的每条测试用例应该是都可以独立运行的
- 测试用例是测试步骤teststep`有序` 集合,每一个测试步骤对应一个 API 的请求描述
- 测试用例集testsuite是测试用例的 `无序` 集合,集合中的测试用例应该都是相互独立,不存在先后依赖关系的;如果确实存在先后依赖关系,那就需要在测试用例中完成依赖的处理
如果对于上述第三点感觉难以理解,不妨看下上图中的示例:
- testcase1 依赖于 testcase2那么就可以在测试步骤teststep12中对 testcase2 进行引用,然后 testcase1 就是完整且可独立运行的;
- 在 testsuite 中testcase1 与 testcase2 相互独立,运行顺序就不再有先后依赖关系了。
## 分层描述详解
理解了测试用例分层模型,接下来我们再来看下在分层模型下,接口、测试用例、测试用例集的描述形式。
### 接口定义API
为了更好地对接口描述进行管理,推荐使用独立的文件对接口描述进行存储,即每个文件对应一个接口描述。
接口定义描述的主要内容包括:**name**、variables、**request**、base_url、validate 等,形式如下:
```yaml
name: get headers
base_url: http://httpbin.org
variables:
expected_status_code: 200
request:
url: /headers
method: GET
validate:
- eq: ["status_code", $expected_status_code]
- eq: [content.headers.Host, "httpbin.org"]
```
其中name 和 request 部分是必须的request 中的描述形式与 [requests.request](http://docs.python-requests.org/en/master/api/) 完全相同。
另外API 描述需要尽量保持完整,做到可以单独运行。如果在接口描述中存在变量引用的情况,可在 variables 中对参数进行定义。通过这种方式,可以很好地实现单个接口的调试。
```bash
$ hrun api/get_headers.yml
INFO Start to run testcase: get headers
headers
INFO GET http://httpbin.org/headers
INFO status_code: 200, response_time(ms): 477.32 ms, response_length: 157 bytes
.
----------------------------------------------------------------------
Ran 1 test in 0.478s
OK
```
### 测试用例testcase
#### 引用接口定义
有了接口的定义描述后,我们编写测试场景时就可以直接引用接口定义了。
在测试步骤teststep可通过 `api` 字段引用接口定义,引用方式为对应 API 文件的路径,绝对路径或相对路径均可。推荐使用相对路径,路径基准为项目根目录,即 `debugtalk.py` 所在的目录路径。
```yaml
- config:
name: "setup and reset all."
variables:
user_agent: 'iOS/10.3'
device_sn: "TESTCASE_SETUP_XXX"
os_platform: 'ios'
app_version: '2.8.6'
base_url: "http://127.0.0.1:5000"
verify: False
output:
- session_token
- test:
name: get token (setup)
api: api/get_token.yml
variables:
user_agent: 'iOS/10.3'
device_sn: $device_sn
os_platform: 'ios'
app_version: '2.8.6'
extract:
- session_token: content.token
validate:
- eq: ["status_code", 200]
- len_eq: ["content.token", 16]
- test:
name: reset all users
api: api/reset_all.yml
variables:
token: $session_token
```
若需要控制或改变接口定义中的参数值,可在测试步骤中指定 variables 参数,覆盖 API 中的 variables 实现。
同样地,在测试步骤中定义 validate 后,也会与 API 中的 validate 合并覆盖。因此推荐的做法是,在 API 定义中的 validate 只描述最基本的校验项,例如 status_code对于与业务逻辑相关的更多校验项在测试步骤的 validate 中进行描述。
#### 引用测试用例
在测试用例的测试步骤中,除了可以引用接口定义,还可以引用其它测试用例。通过这种方式,可以在避免重复描述的同时,解决测试用例的依赖关系,从而保证每个测试用例都是独立可运行的。
在测试步骤teststep可通过 `testcase` 字段引用其它测试用例,引用方式为对应测试用例文件的路径,绝对路径或相对路径均可。推荐使用相对路径,路径基准为项目根目录,即 `debugtalk.py` 所在的目录路径。
例如,在上面的测试用例("setup and reset all.")中,实现了对获取 token 功能的测试;同时,在很多其它功能中都会依赖于获取 token 的功能,如果将该功能的测试步骤脚本拷贝到其它功能的测试用例中,那么就会存在大量重复,当需要对该部分进行修改时就需要修改所有地方,显然不便于维护。
比较好的做法是,在其它功能的测试用例(如创建用户)中,引用获取 token 功能的测试用例testcases/setup.yml作为一个测试步骤从而创建用户"create user and check result.")这个测试用例也变得独立可运行了。
```yaml
- config:
name: "create user and check result."
id: create_user
base_url: "http://127.0.0.1:5000"
variables:
uid: 9001
device_sn: "TESTCASE_CREATE_XXX"
output:
- session_token
- test:
name: setup and reset all (override) for $device_sn.
testcase: testcases/setup.yml
output:
- session_token
- test:
name: create user and check result.
variables:
token: $session_token
testcase: testcases/deps/check_and_create.yml
```
### 测试用例集testsuite
当测试用例数量比较多以后,为了方便管理和实现批量运行,通常需要使用测试用例集来对测试用例进行组织。
在前文的测试用例分层模型中也强调了测试用例集testsuite是测试用例的 `无序` 集合,集合中的测试用例应该都是相互独立,不存在先后依赖关系的;如果确实存在先后依赖关系,那就需要在测试用例中完成依赖的处理。
因为是 `无序` 集合,因此测试用例集的描述形式会与测试用例有些不同,在每个测试用例集文件中,第一层级存在两类字段:
- config: 测试用例集的总体配置参数
- testcases: 值为字典结构无序key 为测试用例的名称value 为测试用例的内容;在引用测试用例时也可以指定 variables实现对引用测试用例中 variables 的覆盖。
#### 非参数化场景
```yaml
config:
name: create users with uid
variables:
device_sn: ${gen_random_string(15)}
var_a: ${gen_random_string(5)}
var_b: $var_a
base_url: "http://127.0.0.1:5000"
testcases:
create user 1000 and check result.:
testcase: testcases/create_user.yml
variables:
uid: 1000
var_c: ${gen_random_string(5)}
var_d: $var_c
create user 1001 and check result.:
testcase: testcases/create_user.yml
variables:
uid: 1001
var_c: ${gen_random_string(5)}
var_d: $var_c
```
#### 参数化场景parameters
对于参数化场景,可通过 parameters 实现,描述形式如下所示。
```yaml
config:
name: create users with parameters
variables:
device_sn: ${gen_random_string(15)}
base_url: "http://127.0.0.1:5000"
testcases:
create user $uid and check result for $device_sn.:
testcase: testcases/create_user.yml
variables:
uid: 1000
device_sn: TESTSUITE_XXX
parameters:
uid: [101, 102, 103]
device_sn: [TESTSUITE_X1, TESTSUITE_X2]
```
参数化后parameters 中的变量将采用笛卡尔积组合形成参数列表,依次覆盖 variables 中的参数,驱动测试用例的运行。
## 文件目录结构管理 && 脚手架工具
在对测试用例文件进行组织管理时,对于文件的存储位置均没有要求和限制,在引用时只需要指定对应的文件路径即可。但从约定大于配置的角度,最好是按照推荐的文件夹名称进行存储管理,并可通过子目录实现项目模块分类管理。
推荐的方式汇总如下:
- `debugtalk.py` 放置在项目根目录下,假设为 `PRJ_ROOT_DIR`
- `.env` 放置在项目根目录下,路径为 `PRJ_ROOT_DIR/.env`
- 接口定义API放置在 `PRJ_ROOT_DIR/api/` 目录下
- 测试用例testcase放置在 `PRJ_ROOT_DIR/testcases/` 目录下
- 测试用例集testsuite文件必须放置在 `PRJ_ROOT_DIR/testsuites/` 目录下
- data 文件夹:存储参数化文件,或者项目依赖的文件,路径为 `PRJ_ROOT_DIR/data/`
- reports 文件夹:存储 HTML 测试报告,生成路径为 `PRJ_ROOT_DIR/reports/`
目录结构如下所示:
```bash
$ tree tests
tests
├── .env
├── data
│ ├── app_version.csv
│ └── account.csv
├── api
│ ├── create_user.yml
│ ├── get_headers.yml
│ ├── get_token.yml
│ ├── get_user.yml
│ └── reset_all.yml
├── debugtalk.py
├── testcases
│ ├── create_user.yml
│ ├── deps
│ │ └── check_and_create.yml
│ └── setup.yml
└── testsuites
├── create_users.yml
└── create_users_with_parameters.yml
```
**项目脚手架**
同时,在 `HttpRunner` 中实现了一个脚手架工具,可以快速创建项目的目录结构。该想法来源于 `Django``django-admin.py startproject project_name`
使用方式也与 `Django` 类似,只需要通过 `--startproject` 指定新项目的名称即可。
```bash
$ hrun --startproject demo
Start to create new project: demo
CWD: /Users/debugtalk/MyProjects/examples
created folder: demo
created folder: demo/api
created folder: demo/testcases
created folder: demo/testsuites
created folder: demo/reports
created file: demo/debugtalk.py
created file: demo/.env
```
## 相关参考
- [《HttpRunner 的测试用例分层机制(已过期)》](/post/HttpRunner-testcase-layer)
- 测试用例分层详细示例:[HttpRunner/tests](https://github.com/HttpRunner/HttpRunner/tree/master/tests)