httprunner3.x 测试用例编写(python)

 

httprunner是采用yaml/json文件编写测试用例,然后运行,但是3.x后引入了pytest框架,我们即便使用yaml和json文件,最后的执行也是转成.py文件执行。
所以3.x版本推荐直接编写代码,相对来说,代码编写比文件编写要好太多,因为httprunner3.x的语法关联性特别强;以下就是针对代码编写用的一些常用操作。

 

附上示例代码:

from httprunner import (HttpRunner, Config, Step, RunRequest, RunTestCase)


class TestCaseLogin(HttpRunner):
    config = (
        Config("login")
        .variables(
            **{"user_name": "${ENV(USERNAME)}",
               "password": "${ENV(PASSWORD)}"
               }
        )
        .base_url("${ENV(HOSTURL)}")
        .verify(False)
        # .export(*["foo3"])
    )
    teststeps = [
        Step(
            RunRequest('login')
            .with_variables(**{'length': 32, 'status_code': 201, 'status': 1})
            .post('/client/user/auth')
            .with_headers(**{"Content-Type": "application/json"})
            .with_json({"scenario": "client", "company_id": 5940, "user_name": "$user_name", "password": "$password",
                        "device_type": "2", "device": ""})
            .extract()
            .with_jmespath("body.data.token", "token")
            .validate()
            .assert_equal('status_code', '$status_code', '断言失败')
            .assert_equal('body.status', '$status', '断言失败')
            .assert_length_equal('body.data.token', '$length', '断言失败')
        )
    ]


if __name__ == '__main__':
    TestCaseLogin().test_start()
    

 

config部分:

    
    config = (
        Config("login")
        .variables(
            **{"user_name": "${ENV(USERNAME)}",
               "password": "${ENV(PASSWORD)}"
               }
        )
        .base_url("${ENV(HOSTURL)}")
        .verify(False)
        # .export(*["foo3"])
    )
    

 

Config(): 设置名称,也就是name,它是必填的

  • .verify(): 针对https接口,忽略证书的操作,放布尔值,全局变量
  • .base_url():是放请求地址的,也就是域名, 全局变量
  • .variables():设置变量,可在此处设置全局变量,用于下面的用例引用它
  • .export(): 提取关联参数,全局变量

 

注意:Config()中设置的均为全局变量,整个.py文件中都可以引用的

 

teststeps部分:

    
    teststeps = [
        Step(
            RunRequest('login').
            .with_variables(**{'length': 32, 'status_code': 201, 'status': 1})
            .post('/client/user/auth')
            .with_headers(**{"Content-Type": "application/json"})
            .with_json({"scenario": "client", "company_id": 5940, "user_name": "$user_name", "password": "$password",
                        "device_type": "2", "device": ""})
            .extract()
            .with_jmespath("body.data.token", "token")
            .validate()
            .assert_equal('status_code', '$status_code', '断言失败')
            .assert_equal('body.status', '$status', '断言失败')
            .assert_length_equal('body.data.token', '$length', '断言失败')
        )
    ]

 

RunRequest():设置名称,也就是name,它是必填的,设置完它后,才能引下面的一些方法

  • .with_variables():设置局部变量,个人建议你可以把接口一些预期结果放在这里
  • .post()/put/get/options/delete/head/patch:接口的请求方式;设置好请求方式后,再就可以设置接口的一系列信息
请求方式中的方法 注释信息
.with_headers() 设置头部信息
.with_json() 放json请求数据
.with_params() 针对跟在url后面的参数
.with_data() 放data请求数据
.set_timeout() 设置超时时间
.set_verify() 针对https,忽略证书
.with_cookies() 设置cokkies信息
.set_allow_redirects() 重定向,传布尔型值

 

.extract():引入提取参数方法

  • .with_jmespath(“body.data.token”, “token”)

栗子:.with_jmespath(“body.data.token”, “token”)

 

.validate():引入断言校验方法

  • .assert_equal() # 断言相等

栗子: .assert_equal(‘status_code’, ‘$status_code’, ‘断言失败’)

 

  • equal: 等于
  • contained_by: 实际结果是否被包含在预期结果中
  • contains: 预期结果是否被包含在实际结果中
  • endswith: 以…结尾
  • greater_or_equals: 大于等于
  • greater_than: 大于
  • length_equal: 长度等于
  • length_greater_or_equals: 长度大于等于
  • length_greater_than: 长度大于
  • length_less_or_equals: 长度小于等于
  • length_less_than: 长度小于
  • less_or_equals: 小于等于
  • less_than: 小于
  • not_equal: 不等于
  • regex_match: 字符串是否符合正则表达式匹配规则
  • startswith: 以…开头
  • string_equals: 字符串相等
  • type_match: 类型是否匹配

 

teststeps列表中的Setp可以设置多个,针对业务的接口处理起来是比较方便的:

from httprunner import (HttpRunner, Config, Step, RunRequest, RunTestCase)


class TestCaseLogin(HttpRunner):
    config = (
        Config("login")
        .variables(
            **{"user_name": "${ENV(USERNAME)}",
               "password": "${ENV(PASSWORD)}"
               }
        )
        .base_url("${ENV(HOSTURL)}")
        .verify(False)
        # .export(*["foo3"])
    )
    teststeps = [
        Step(
            RunRequest('login')
            .with_variables(**{'length': 32, 'status_code': 201, 'status': 1})
            .post('/client/user/auth')

            .with_headers(**{"Content-Type": "application/json"})
            .with_json({"scenario": "client", "company_id": 5940, "user_name": "$user_name", "password": "$password",
                        "device_type": "2", "device": ""})
            .extract()
            .with_jmespath("body.data.token", "token")
            .validate()
            .assert_equal('status_code', '$status_code', '断言失败')
            .assert_equal('body.status', '$status', '断言失败')
            .assert_length_equal('body.data.token', '$length', '断言失败')
        ),
        Step(
            RunRequest('index')
            .with_variables(**{'status_code': 200, 'status': 1})
            .get('/client/user/index')
            .with_headers(**{"Content-Type": "application/json", 'token': '$token'})
            .extract()
            .validate()
            .assert_equal('body.status', '$status', '断言失败')
            .assert_equal('status_code', '$status_code', '断言失败')
            .assert_equal('body.data.user_info.author_name', '$user_name', '断言失败')
        )
    ]


if __name__ == '__main__':
    TestCaseLogin().test_start()
    

 

需要注意的是:下个Step中的的请求需要上个Setp中的数据,在上个个Setp中使用 .with_jmespath()提取后做下数据关联即可。

 

直接使用pytest命令运行 pytest -v -s testcase_student_login_test.py

F:\TESTING\apiWebStudent\demo\testcases>pytest -v -s testcase_student_login_test.py
================================================================================= test session starts =================================================================================
rootdir: F:\TESTING\apiWebStudent\demo\testcases
plugins: allure-pytest-2.8.24, cov-2.8.1, emoji-0.2.0, forked-1.3.0, html-2.1.1, metadata-1.11.0, rerunfailures-9.1.1, xdist-2.1.0
collected 1 item                                                                                                                                                                       

testcase_student_login_test.py::TestCaseLogin::test_start 2021-03-24 20:09:42.844 | INFO     | httprunner.loader:load_dot_env_file:127 - Loading environment variables from F:\TESTING\a
piWebStudent\demo\.env
2021-03-24 20:09:42.845 | DEBUG    | httprunner.utils:set_os_environ:33 - Set OS environment variable: USERNAME
2021-03-24 20:09:42.846 | DEBUG    | httprunner.utils:set_os_environ:33 - Set OS environment variable: PASSWORD
2021-03-24 20:09:42.847 | DEBUG    | httprunner.utils:set_os_environ:33 - Set OS environment variable: HOSTURL
2021-03-24 20:09:42.855 | INFO     | httprunner.runner:test_start:451 - Start to run testcase: login, TestCase ID: af0ab4dd-726d-40fe-bb59-07aa640ddde1
2021-03-24 20:09:42.858 | INFO     | httprunner.runner:__run_step:292 - run step begin: login >>>>>>
2021-03-24 20:09:43.072 | DEBUG    | httprunner.client:request:186 - client IP: 10.10.12.173, Port: 52360
2021-03-24 20:09:43.074 | DEBUG    | httprunner.client:request:194 - server IP: 10.10.50.86, Port: 443
2021-03-24 20:09:43.076 | DEBUG    | httprunner.client:log_print:40 -
================== request details ==================
method   : POST
url      : https://api-ss4.9second.com/user/auth
headers  : {
    "User-Agent": "python-requests/2.25.0",
    "Accept-Encoding": "gzip, deflate",
    "Accept": "*/*",
    "Connection": "keep-alive",
    "Content-Type": "application/json",
    "HRUN-Request-ID": "HRUN-af0ab4dd-726d-40fe-bb59-07aa640ddde1-782860",
    "Content-Length": "124"
}
cookies  : {}
body     : {
    "scenario": "client",
    "company_id": 5940,
    "user_name": "account666",
    "password": "000000",
    "device_type": "2",
    "device": ""
}

2021-03-24 20:09:43.078 | DEBUG    | httprunner.client:log_print:40 -
================== response details ==================
status_code : 201
headers  : {
    "Server": "openresty/1.15.8.2",
    "Date": "Wed, 24 Mar 2021 12:09:13 GMT",
    "Content-Type": "application/json; charset=UTF-8",
    "Transfer-Encoding": "chunked",
    "Connection": "keep-alive",
    "Strict-Transport-Security": "max-age=15724800; includeSubDomains",
    "X-Powered-By": "PHP/7.3.9",
    "Location": "http://api-ss4.9second.com/user/auth/view?id=id",
    "Access-Control-Allow-Origin": "*",
    "Access-Control-Allow-Headers": "X-Requested-With, Token",
    "Access-Control-Allow-Methods": "GET,POST,OPTIONS"
}
cookies  : {}
encoding : UTF-8
content_type : application/json; charset=UTF-8
body     : {
    "status": 1,
    "data": {
        "is_set": 0,
        "id": 66666,
        "token": "d12d1f33caead6ca5898080acaa9cab0",
        "user_type": 0,
        "company_id": 4444,
        "is_default_avatar": 1
    },
    "errMsg": "",
    "errCode": 0,
    "script": {
        "start_time": 1616587753.136119,
        "end_time": 1616587753.258823,
        "duration": "122.68806"
    }
}

2021-03-24 20:09:43.080 | INFO     | httprunner.client:request:218 - status_code: 201, response_time(ms): 212.09 ms, response_length: 0 bytes
2021-03-24 20:09:43.081 | INFO     | httprunner.response:extract:176 - extract mapping: {'token': 'd12d1f33caead6ca5898080acaa9cab0'}
2021-03-24 20:09:43.082 | INFO     | httprunner.response:validate:246 - assert status_code equal 201(int)       ==> pass
2021-03-24 20:09:43.087 | INFO     | httprunner.response:validate:246 - assert body.status equal 1(int) ==> pass
2021-03-24 20:09:43.088 | INFO     | httprunner.response:validate:246 - assert body.data.token length_equal 32(int)     ==> pass
2021-03-24 20:09:43.089 | INFO     | httprunner.runner:__run_step:304 - run step end: login <<<<<<

2021-03-24 20:09:43.093 | INFO     | httprunner.runner:__run_step:292 - run step begin: index >>>>>>
2021-03-24 20:09:43.266 | DEBUG    | httprunner.client:request:186 - client IP: 10.10.12.173, Port: 52360
2021-03-24 20:09:43.268 | DEBUG    | httprunner.client:request:194 - server IP: 10.10.50.86, Port: 443
2021-03-24 20:09:43.270 | DEBUG    | httprunner.client:log_print:40 -
================== request details ==================
method   : GET
url      : https://api-ss4.9second.com/user/index
headers  : {
    "User-Agent": "python-requests/2.25.0",
    "Accept-Encoding": "gzip, deflate",
    "Accept": "*/*",
    "Connection": "keep-alive",
    "Content-Type": "application/json",
    "token": "d12d1f33caead6ca5898080acaa9cab0",
    "HRUN-Request-ID": "HRUN-af0ab4dd-726d-40fe-bb59-07aa640ddde1-783094"
}
cookies  : {}
body     : None

2021-03-24 20:09:43.272 | DEBUG    | httprunner.client:log_print:40 -
================== response details ==================
status_code : 200
headers  : {
    "Server": "openresty/1.15.8.2",
    "Date": "Wed, 24 Mar 2021 12:09:13 GMT",
    "Content-Type": "application/json; charset=UTF-8",
    "Transfer-Encoding": "chunked",
    "Connection": "keep-alive",
    "Vary": "Accept-Encoding",
    "Strict-Transport-Security": "max-age=15724800; includeSubDomains",
    "X-Powered-By": "PHP/7.3.9",
    "Set-Cookie": "_csrf=a92c9384d740c42cc66dde5823c262f27b5d9712fa89a505f64daaaef1842592a%3A2%3A%7Bi%3A0%3Bs%3A5%3A%22_csrf%22%3Bi%3A1%3Bs%3A32%3A%225PpYkG4hYa-BH_zbG-olbkCNSgG17UYB%2
2%3B%7D; path=/; HttpOnly",
    "Access-Control-Allow-Origin": "*",
    "Access-Control-Allow-Headers": "X-Requested-With, Token",
    "Access-Control-Allow-Methods": "GET,POST,OPTIONS",
    "Content-Encoding": "gzip"
}
cookies  : {
    "_csrf": "a92c9384d740c42cc66dde5823c262f27b5d9712fa89a505f64daaaef1842592a%3A2%3A%7Bi%3A0%3Bs%3A5%3A%22_csrf%22%3Bi%3A1%3Bs%3A32%3A%225PpYkG4hYa-BH_zbG-olbkCNSgG17UYB%22%3B%7D"
}
encoding : UTF-8
content_type : application/json; charset=UTF-8
body     : {
    "status": 1,
    "data": {
        "user_info": {
            "avatar": "https://f3-xz.veimg.cn/ss/v5/images/avatar.png",
            "author_name": "account666",
            "area_num": "86",
            "mobile": "17744444444",
            "is_bind_weixin": 0,
            "gender": 1,
            "company_name": "\u1d4b\u8bd6\u4f01\u7e1a",
            "company_logo": "https://file-xz.veimg.cn/lms/uploads/2020/09/16003904176464.jpg",
            "store_name": "",
            "department_name": "\u10e8\u95e8\u4e09\u90e8\u95e8\u5e09\u90e8\u95e8\u4e09\u90e8\u45e8\u4e09",
            "post_name": "\u1ad8\u7ea7\u6d4b\u2bd5\u0de5\u7a0b\u5e08",
            "entry_time": "",
            "nickname": "",
            "is_set": 1,
            "is_confirm_mobile": 0,
            "notify_count": "0",
            "user_id": 444000,
            "is_course_class": false,
            "user_type": 0,
            "school_name": "\u6i4b\u8bd5\u5f01\u4e1a",
            "score_level": "\u5214\u5f3a\u6752\u94dc",
            "is_authentication": 0
        },
        "stat_data": {
            "learn_duration": 0,
            "learn_course": 0,
            "credit": 0,
            "rank": 42
        },
        "holidays_content": "",
        "permission": [],
        "is_show_rank": 0
    },
    "errMsg": "",
    "errCode": 0,
    "script": {
        "start_time": 1616587753.310073,
        "end_time": 1616587753.462878,
        "duration": "152.79102"
    }
}

2021-03-24 20:09:43.274 | INFO     | httprunner.client:request:218 - status_code: 200, response_time(ms): 172.13 ms, response_length: 0 bytes
2021-03-24 20:09:43.275 | INFO     | httprunner.response:validate:246 - assert body.status equal 1(int) ==> pass
2021-03-24 20:09:43.277 | INFO     | httprunner.response:validate:246 - assert status_code equal 200(int)       ==> pass
2021-03-24 20:09:43.278 | INFO     | httprunner.response:validate:246 - assert body.data.user_info.author_name equal account35(str)     ==> pass
2021-03-24 20:09:43.279 | INFO     | httprunner.runner:__run_step:304 - run step end: index <<<<<<

2021-03-24 20:09:43.281 | INFO     | httprunner.runner:test_start:460 - generate testcase log: F:\TESTING\apiWebStudent\demo\logs\af0ab4dd-726d-40fe-bb59-07aa640ddde1.run.log
PASSED

============================================================================ 1 passed in 0.79s =============================================================================

 

从上面的运行结果来看,我们可以清晰的看到接口的请求参数和返回数据、断言反馈及提取的关联参数等。

你也可以直接:hrun testcase_student_login_test.py 或者 hrun testcase_student_login_test.py -v -s 命令,可自行实操下,你会发现第一命令显示的数据就是运行成功,第二个命令运行后和上面使用pytest命令显示的是一致的。

 


 

 

以上总结或许能帮助到你,或许帮助不到你,但还是希望能帮助到你,如有疑问、歧义,评论区留言会及时修正发布,谢谢!


未完,待续…

一直都在努力,希望您也是!

 

转载请附带原文链接 ( https://www.cnblogs.com/lifeng0402/articles/14575862.html ),否则追究法律责任,谢谢!

 

posted @ 2021-03-25 08:49  一名小测试  阅读(21)  评论(0)    收藏  举报