HttpRunner V3.x学习笔记系列 (四) -- 测试用例结构及用例配置config


一、官方首推pytest格式

httprunner可以支持三种格式的用例,分别是pytest、yaml和json。yaml和json是以前的版本所使用的用例格式,但是在3.x版本上,官方强烈建议使用的是pytest格式的用例。

 

上图是来自官方的用例格式关系图,可以看出来,httprunner再对于第三方导出的har文件进行了转换处理,有的人喜欢转换成json,有的人喜欢转换成yaml。但是最终,还是通过解析json格式的文件,生成pytest的python文件。

二、用例结构

录制生成的case很便捷,但是这并不是说,不需要我们做任何的改动了。在实践的过程中,我们仍然会根据我们实际项目的不同需求来对case作进一步的调整,所以彻底的了解case的构造尤为重要。
首先,我录制了一个百度搜索“httprunner”的一个请求,转换成pytest文件后如下:

 

可以看到:

每个测试用例都是 HttpRunner 的子类(一个类即为一个测试用例),并且必须具有两个类属性:configteststeps

  • 每个testcase都是HttpRunner的子类
  • 必须有两个类属性:config和teststeps。
  • 单个teststeps列表中的单个Step内部通过链式调用(RunRequest().get().with_params().with_header().with_cookies().validate().assert_equal())
  1. config:配置测试用例级设置,包括基础url、验证、变量、导出。
  2. teststeps:teststep的列表(list[Step]),每个步骤对应于一个API请求,也可以调用另一个testcase。此外,还支持variables/extract/validate/hooks机制来创建极其复杂的测试场景。
  3. 链式调用:HttpRunner v3.x 的最强大功能之一是链式调用,使用它无需记住任何测试用例格式的详细信息,并且在 IDE 中编写测试用例时可以智能完成。可以看到一个case的请求,经过了各个环节的调用,这也是httprunner 3.x版本一大亮点。

 

 

三、httprunner的用例结构

补一个官方完整的一个demo代码,并说说httprunner中的用例与自己编写的测试用例之间的联系。

 1 # NOTE: Generated By HttpRunner v3.1.4
 2 # FROM: testcases\demo_testcase_request.yml
 3 
 4 
 5 from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase
 6 
 7 
 8 class TestCaseDemoTestcaseRequest(HttpRunner):
 9 
10     config = (
11         Config("request methods testcase with functions")
12         .variables(
13             **{
14                 "foo1": "config_bar1",
15                 "foo2": "config_bar2",
16                 "expect_foo1": "config_bar1",
17                 "expect_foo2": "config_bar2",
18             }
19         )
20         .base_url("https://postman-echo.com")
21         .verify(False)
22         .export(*["foo3"])
23     )
24 
25     teststeps = [
26         Step(
27             RunRequest("get with params")
28             .with_variables(
29                 **{"foo1": "bar11", "foo2": "bar21", "sum_v": "${sum_two(1, 2)}"}
30             )
31             .get("/get")
32             .with_params(**{"foo1": "$foo1", "foo2": "$foo2", "sum_v": "$sum_v"})
33             .with_headers(**{"User-Agent": "HttpRunner/${get_httprunner_version()}"})
34             .extract()
35             .with_jmespath("body.args.foo2", "foo3")
36             .validate()
37             .assert_equal("status_code", 200)
38             .assert_equal("body.args.foo1", "bar11")
39             .assert_equal("body.args.sum_v", "3")
40             .assert_equal("body.args.foo2", "bar21")
41         ),
42         Step(
43             RunRequest("post raw text")
44             .with_variables(**{"foo1": "bar12", "foo3": "bar32"})
45             .post("/post")
46             .with_headers(
47                 **{
48                     "User-Agent": "HttpRunner/${get_httprunner_version()}",
49                     "Content-Type": "text/plain",
50                 }
51             )
52             .with_data(
53                 "This is expected to be sent back as part of response body: $foo1-$foo2-$foo3."
54             )
55             .validate()
56             .assert_equal("status_code", 200)
57             .assert_equal(
58                 "body.data",
59                 "This is expected to be sent back as part of response body: bar12-$expect_foo2-bar32.",
60             )
61         ),
62         Step(
63             RunRequest("post form data")
64             .with_variables(**{"foo2": "bar23"})
65             .post("/post")
66             .with_headers(
67                 **{
68                     "User-Agent": "HttpRunner/${get_httprunner_version()}",
69                     "Content-Type": "application/x-www-form-urlencoded",
70                 }
71             )
72             .with_data("foo1=$foo1&foo2=$foo2&foo3=$foo3")
73             .validate()
74             .assert_equal("status_code", 200)
75             .assert_equal("body.form.foo1", "$expect_foo1")
76             .assert_equal("body.form.foo2", "bar23")
77             .assert_equal("body.form.foo3", "bar21")
78         ),
79     ]
80 
81 
82 if __name__ == "__main__":
83     TestCaseDemoTestcaseRequest().test_start()
  1. httprunner中的testcase,其实说的就是上面的这一整个Python文件。
  2. teststeps列表中的Step,其实就是自己编写case时候的一个个def test_xxx():pass。
  3. 而每一个Step内部,依然是按照 传参——调用接口——断言,这样的过程来的。

 

 四、测试用例-config

在配置中,我们可以配置测试用例级级别的一些设置,比如基础url、验证、变量、导出。

# NOTE: Generated By HttpRunner v3.1.4
# FROM: testcases\demo_testcase_request.yml


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


class TestCaseDemoTestcaseRequest(HttpRunner):

    config = (
        Config("request methods testcase with functions")
        .variables(
            **{
                "foo1": "config_bar1",
                "foo2": "config_bar2",
                "expect_foo1": "config_bar1",
                "expect_foo2": "config_bar2",
            }
        )
        .base_url("https://postman-echo.com")
        .verify(False)
        .export(*["foo3"])
    )

    teststeps = [
        Step(
            RunRequest("get with params")
            .with_variables(
                **{"foo1": "bar11", "foo2": "bar21", "sum_v": "${sum_two(1, 2)}"}
            )
            .get("/get")
            .with_params(**{"foo1": "$foo1", "foo2": "$foo2", "sum_v": "$sum_v"})
            .with_headers(**{"User-Agent": "HttpRunner/${get_httprunner_version()}"})
            .extract()
            .with_jmespath("body.args.foo2", "foo3")
            .validate()
            .assert_equal("status_code", 200)
            .assert_equal("body.args.foo1", "bar11")
            .assert_equal("body.args.sum_v", "3")
            .assert_equal("body.args.foo2", "bar21")
        ),
        Step(
            RunRequest("post raw text")
            .with_variables(**{"foo1": "bar12", "foo3": "bar32"})
            .post("/post")
            .with_headers(
                **{
                    "User-Agent": "HttpRunner/${get_httprunner_version()}",
                    "Content-Type": "text/plain",
                }
            )
            .with_data(
                "This is expected to be sent back as part of response body: $foo1-$foo2-$foo3."
            )
            .validate()
            .assert_equal("status_code", 200)
            .assert_equal(
                "body.data",
                "This is expected to be sent back as part of response body: bar12-$expect_foo2-bar32.",
            )
        ),
        Step(
            RunRequest("post form data")
            .with_variables(**{"foo2": "bar23"})
            .post("/post")
            .with_headers(
                **{
                    "User-Agent": "HttpRunner/${get_httprunner_version()}",
                    "Content-Type": "application/x-www-form-urlencoded",
                }
            )
            .with_data("foo1=$foo1&foo2=$foo2&foo3=$foo3")
            .validate()
            .assert_equal("status_code", 200)
            .assert_equal("body.form.foo1", "$expect_foo1")
            .assert_equal("body.form.foo2", "bar23")
            .assert_equal("body.form.foo3", "bar21")
        ),
    ]


if __name__ == "__main__":
    TestCaseDemoTestcaseRequest().test_start()

上面是官方给出的一个例子

(1)  name(必填)

即用例名称,这是一个必填参数。测试用例名称,将显示在执行日志和测试报告中。比如,官方给出的case里,加入name。

 

执行用例:

pytest -s -v demo_testcase_ref_test.py

 运行后,在debug日志里,可以看到用例名称被展示出来。

 

 (2)  base_url(选填)

这个配置一般在多环境切换中最常用。
比如你的这套测试用例在多套环境(测试环境,生成环境)都要使用,那么就可以把基础地址(举例http://demo.qa.com),设置进去。在后面的teststep中,只需要填上接口的相对路径就好了(举例 /get)。
这样的话,切换环境运行,只需要修改base_url即可。

 

 (3) variables(选填) -- 变量和值一一对应

在 HttpRunner 中,支持变量声明(variables)和引用($var)的机制。调用函数(${func($var)})

在 config 和 test 中均可以通过 variables 关键字定义变量,然后在测试步骤中可以通过 $ + 变量名称 的方式引用变量。

区别在于:

在 config 中定义的变量为全局的,整个测试用例(testcase)的所有地方均可以引用;

在 test 中定义的变量作用域仅局限于当前测试步骤(teststep)

config这里可以存放一些公共的变量,可以在测试用例里引用。这里大家可以记住这个“公共”的词眼,因为在后面的Step中,还会有步骤变量。

比如说,我的接口有个传参是不变的,比如用户名username,而且后面的每个Step都会用到这个传参,那么username就可以放在config的公共变量里。
另外,Step里的变量优先级是比config里的变量要高的,如果step和config中variables声明的参数名相同,在运行测试用例的时候会优先取step里面的参数值。

注意:一般写用例的时候,最好把可能会变的参数单独写个变量。做到测试数据和代码的分离,以便后续维护。

全局变量

如果要设置一个全局变量,需把变量声明(variables)放到config下

pytest格式:

# NOTE: Generated By HttpRunner v3.1.4
# FROM: testcases\demo_testcase_request.yml


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


class TestCaseDemoTestcaseRequest(HttpRunner):

    config = (
        Config("request methods testcase with functions")
        .variables(
            **{
                "foo1": "config_bar1",
                "foo2": "config_bar2",
                "expect_foo1": "config_bar1",
                "expect_foo2": "config_bar2",
            }
        )
        .base_url("https://postman-echo.com")
        .verify(False)
        .export(*["foo3"])
    )

    teststeps = [
        Step(
            RunRequest("get with params")
            .with_variables(
                **{"foo1": "bar11", "foo2": "bar21", "sum_v": "${sum_two(1, 2)}"}
            )
            .get("/get")
            .with_params(**{"foo1": "$foo1", "foo2": "$foo2", "sum_v": "$sum_v"})
            .with_headers(**{"User-Agent": "HttpRunner/${get_httprunner_version()}"})
            .extract()
            .with_jmespath("body.args.foo2", "foo3")
            .validate()
            .assert_equal("status_code", 200)
            .assert_equal("body.args.foo1", "bar11")
            .assert_equal("body.args.sum_v", "3")
            .assert_equal("body.args.foo2", "bar21")
        ),
        Step(
            RunRequest("post raw text")
            .with_variables(**{"foo1": "bar12", "foo3": "bar32"})
            .post("/post")
            .with_headers(
                **{
                    "User-Agent": "HttpRunner/${get_httprunner_version()}",
                    "Content-Type": "text/plain",
                }
            )
            .with_data(
                "This is expected to be sent back as part of response body: $foo1-$foo2-$foo3."
            )
            .validate()
            .assert_equal("status_code", 200)
            .assert_equal(
                "body.data",
                "This is expected to be sent back as part of response body: bar12-$expect_foo2-bar32.",
            )
        ),
        Step(
            RunRequest("post form data")
            .with_variables(**{"foo2": "bar23"})
            .post("/post")
            .with_headers(
                **{
                    "User-Agent": "HttpRunner/${get_httprunner_version()}",
                    "Content-Type": "application/x-www-form-urlencoded",
                }
            )
            .with_data("foo1=$foo1&foo2=$foo2&foo3=$foo3")
            .validate()
            .assert_equal("status_code", 200)
            .assert_equal("body.form.foo1", "$expect_foo1")
            .assert_equal("body.form.foo2", "bar23")
            .assert_equal("body.form.foo3", "bar21")
        ),
    ]


if __name__ == "__main__":
    TestCaseDemoTestcaseRequest().test_start()

 

 ymal格式:

config:
    name: "request methods testcase with functions"
    variables:
        foo1: config_bar1
        foo2: config_bar2
        expect_foo1: config_bar1
        expect_foo2: config_bar2
    base_url: "https://postman-echo.com"
    verify: False
    export: ["foo3"]

teststeps:
-
    name: get with params
    variables:
        foo1: bar11
        foo2: bar21
        sum_v: "${sum_two(1, 2)}"
    request:
        method: GET
        url: /get
        params:
            foo1: $foo1
            foo2: $foo2
            sum_v: $sum_v
        headers:
            User-Agent: HttpRunner/${get_httprunner_version()}
    extract:
        foo3: "body.args.foo2"
    validate:
        - eq: ["status_code", 200]
        - eq: ["body.args.foo1", "bar11"]
        - eq: ["body.args.sum_v", "3"]
        - eq: ["body.args.foo2", "bar21"]
-
    name: post raw text
    variables:
        foo1: "bar12"
        foo3: "bar32"
    request:
        method: POST
        url: /post
        headers:
            User-Agent: HttpRunner/${get_httprunner_version()}
            Content-Type: "text/plain"
        data: "This is expected to be sent back as part of response body: $foo1-$foo2-$foo3."
    validate:
        - eq: ["status_code", 200]
        - eq: ["body.data", "This is expected to be sent back as part of response body: bar12-$expect_foo2-bar32."]
-
    name: post form data
    variables:
        foo2: bar23
    request:
        method: POST
        url: /post
        headers:
            User-Agent: HttpRunner/${get_httprunner_version()}
            Content-Type: "application/x-www-form-urlencoded"
        data: "foo1=$foo1&foo2=$foo2&foo3=$foo3"
    validate:
        - eq: ["status_code", 200]
        - eq: ["body.form.foo1", "$expect_foo1"]
        - eq: ["body.form.foo2", "bar23"]
        - eq: ["body.form.foo3", "bar21"]

引用foo1和foo2变量用$foo1,$foo2

 

局部变量

如果在step下声明的变量,作用域只在当前step下有效。声明变量用with_variables,变量和对应值用键值对,如

Step(
            RunRequest("post raw text")
            .with_variables(**{"foo1": "bar12", "foo3": "bar32"})
            .post("/post")
            .with_headers(
                **{
                    "User-Agent": "HttpRunner/${get_httprunner_version()}",
                    "Content-Type": "text/plain",
                }
            )
            .with_data(
                "This is expected to be sent back as part of response body: $foo1-$foo2-$foo3."
            )
            .validate()
            .assert_equal("status_code", 200)
            .assert_equal(
                "body.data",
                "This is expected to be sent back as part of response body: bar12-$expect_foo2-bar32.",
            )
        ),

完整代码如下:

# NOTE: Generated By HttpRunner v3.1.4
# FROM: testcases\demo_testcase_request.yml


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


class TestCaseDemoTestcaseRequest(HttpRunner):

    config = (
        Config("request methods testcase with functions")
        .variables(
            **{
                "foo1": "config_bar1",
                "foo2": "config_bar2",
                "expect_foo1": "config_bar1",
                "expect_foo2": "config_bar2",
            }
        )
        .base_url("https://postman-echo.com")
        .verify(False)
        .export(*["foo3"])
    )

    teststeps = [
        Step(
            RunRequest("get with params")
            .with_variables(
                **{"foo1": "bar11", "foo2": "bar21", "sum_v": "${sum_two(1, 2)}"}
            )
            .get("/get")
            .with_params(**{"foo1": "$foo1", "foo2": "$foo2", "sum_v": "$sum_v"})
            .with_headers(**{"User-Agent": "HttpRunner/${get_httprunner_version()}"})
            .extract()
            .with_jmespath("body.args.foo2", "foo3")
            .validate()
            .assert_equal("status_code", 200)
            .assert_equal("body.args.foo1", "bar11")
            .assert_equal("body.args.sum_v", "3")
            .assert_equal("body.args.foo2", "bar21")
        ),
        Step(
            RunRequest("post raw text")
            .with_variables(**{"foo1": "bar12", "foo3": "bar32"})
            .post("/post")
            .with_headers(
                **{
                    "User-Agent": "HttpRunner/${get_httprunner_version()}",
                    "Content-Type": "text/plain",
                }
            )
            .with_data(
                "This is expected to be sent back as part of response body: $foo1-$foo2-$foo3."
            )
            .validate()
            .assert_equal("status_code", 200)
            .assert_equal(
                "body.data",
                "This is expected to be sent back as part of response body: bar12-$expect_foo2-bar32.",
            )
        ),
        Step(
            RunRequest("post form data")
            .with_variables(**{"foo2": "bar23"})
            .post("/post")
            .with_headers(
                **{
                    "User-Agent": "HttpRunner/${get_httprunner_version()}",
                    "Content-Type": "application/x-www-form-urlencoded",
                }
            )
            .with_data("foo1=$foo1&foo2=$foo2&foo3=$foo3")
            .validate()
            .assert_equal("status_code", 200)
            .assert_equal("body.form.foo1", "$expect_foo1")
            .assert_equal("body.form.foo2", "bar23")
            .assert_equal("body.form.foo3", "bar21")
        ),
    ]


if __name__ == "__main__":
    TestCaseDemoTestcaseRequest().test_start()

 

(4) verify(选填)

 request请求一个https链接时,会验证一次SSL证书。当目标网站使用的是自签名证书时,则会抛出下图的异常。

request模块发送请求函数有个参数verify值默认为True

verify用来决定是否验证服务器TLS证书的开关。
通常设置为False,当请求https请求时,就会跳过验证。如果你运行时候发现抛错SSLError,可以检查一下是不是verify没传,或者设置了True。

解决方法:

在request下添加一个verify参数,值为false

config:
    name: "request methods testcase: reference testcase"
    variables:
        foo1: testsuite_config_bar1
        expect_foo1: testsuite_config_bar1
        expect_foo2: config_bar2
    base_url: "https://postman-echo.com" verify: False #全局设置 request忽略对SSL证书的校验

teststeps:
-
    name: request with functions
    variables:
        foo1: testcase_ref_bar1
        expect_foo1: testcase_ref_bar1
    testcase: testcases/demo_testcase_request.yml
    export:
        - foo3
-
    name: post form data
    variables:
        foo1: bar1
    request:
        verify:False # 局部设置 只对当前用例有效 request忽略对SSL证书的校验
        method: POST
        url: /post
        headers:
            User-Agent: HttpRunner/${get_httprunner_version()}
            Content-Type: "application/x-www-form-urlencoded"
        data: "foo1=$foo1&foo2=$foo3"
    validate:
        - eq: ["status_code", 200]
        - eq: ["body.form.foo1", "bar1"]
        - eq: ["body.form.foo2", "bar21"]

 

(5) export(选填)

 导出的变量,主要是用于Step之间参数的传递。还是以上面的官方代码为例:

可以指定要导出的变量,以供后续Step引用。
可以看的.export()内部是一个列表[],这里可以用来导出多个变量。

  1. 在config中配置export“foo3”这个变量。
  2. 在第一个Step中,.extract() 提取了"body.args.foo2"给变量“foo3”。
  3. 在第二个Step中,引用变量"foo3"。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM