• httprunner4学习总结6 – 手动编写测试用例


    1、pytest格式测试用例基本内容

    import pytest
    from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase
    from lib.common.config_operate import read_ini_config
    from testcases.remote_expert.test_001_banner import (
        TestCaseTest001Banner as Banner001,
    )
    from testcases.remote_expert.test_003_banner import (
        TestCaseTest003Banner as Banner003,
    )
    
    
    @pytest.mark.skipif(
        read_ini_config("Header", "accept-language") == "zh-CN", reason="仅适用于地球外的测试环境"
    )
    class TestCaseTest002Banner(HttpRunner):
    
        config = (
            Config("开启和关闭banner成功")
            # 这里可以替换需要配置的参数,当调用用例的时候可以使用 with_variables()重写参数的值
            .variables(
                **{
                    "xx": "xx",
                    "yy": "yy",
                }
            )
            .base_url("${read_ini_config(Host, rem_host_001)}")
            .verify(False)
            .export("code")
        )
    
        teststeps = [
            # 测试步骤1
            Step(
                RunTestCase("前置1:添加一条banner数据")
                .setup_hook("${setup_clean_data()}")  # 调用用例前执行测试前置
                .with_variables(  # 更新用例里面的字段值
                    **{
                        "xx": "yy",
                    }
                )
                .call(Banner001)  # 调用用例
                .teardown_hook("${teardown_clean_data()}")  # 测试后置
                .export("xx")  # 导出某个值,供下面的步骤使用。这个值来自于本条用例响应内容with_jmespath()
            ),
            Step(RunTestCase("前置2:获取banner页第一行数据ID").call(Banner003).export("id")),
            Step(
                RunRequest("步骤1:关闭 banner ")
                .with_variables(**{"xx": "as"})
                .setup_hook("${setup_clean_data()}")
                .post(
                    "/xxxapp/xxxv1/xxxStatus"
                )
                .with_headers(
                    **{
                        "accept-language": "${read_ini_config(Header, accept-language)}",
                        "autel-token": "${get_login_info(expert_001, token)}",
                    }
                )
                .with_json({"id": "$id", "displayStatus": False})
                .extract()
                .with_jmespath("body.code", "code")
                .validate()
                .assert_equal("status_code", 200)
                .assert_equal("body.code", "200")
                .assert_equal("body.message", "success")
                .assert_equal("body.data", True)
            ),
        ]
    
    
    if __name__ == "__main__":
        TestCaseTest002Banner().test_start()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    2、测试用例增强(参考后面的示例)

    • variables 变量

    变量优先级:step variables > session variables(runtestcase时带的变量) > parameter variables > config variables

    • extract 参数提取
    • debugtalk.py 自定义函数
    • parameterize 参数化数据驱动
    • hook 机制
    • validate 结果校验

    3、完整的 pytest 格式的测试用例

    # demo_banner_test.py
    
    import pytest
    from httprunner import HttpRunner, Config, Step, RunRequest, RunTestCase
    from testcases.pytest测试用例示例.test_001_banner import (
        TestCaseTest001Banner as Banner001,
    )
    from testcases.pytest测试用例示例.test_003_banner import (
        TestCaseTest003Banner as Banner003,
    )
    from httprunner import Parameters
    from lib.common.config_operate import read_ini_config
    
    
    @pytest.mark.skipif(
        read_ini_config("Header", "accept-language") == "zh-CN", reason="仅适用于地球外的测试环境"
    )
    class TestCaseTest002Banner(HttpRunner):
        # 变量_全局变量:字段取值参数化
        @pytest.mark.parametrize(
            "param",
            Parameters(
                {
                    "title": "${get_user_id(10)}",
                    "user": ["user1", "user2"],
                    "title-user": [("demo4", "4"), ("demo5", "5"), ("dmeo6", "6")],
                }
            ),
        )
        def test_start(self, param):
            super().test_start(param)
    
        config = (
            Config("开启和关闭banner成功")
            # 变量_全局变量:这里可以替换需要配置的参数,当调用用例的时候可以使用 with_variables()重写参数的值。这里是这条测试用例的全局变量。优先级没有测试步骤里面的高
            .variables(
                **{
                    "xx": "xx",
                    "yy": "yy",
                }
            )
            .base_url("${read_ini_config(Host, rem_host_001)}")
            .verify(False)
            # 变量_局部变量:该用例被调用时传递出去的变量,可供其他脚本使用
            .export("code")
        )
    
        teststeps = [
            # 测试步骤1
            Step(
                RunTestCase("前置1:添加一条banner数据")
                .setup_hook("${setup_clean_data()}")  # 调用用例前执行测试前置
                # 变量_局部变量:更新某个 step 里面的字段值
                .with_variables(
                    **{
                        "xx": "yy",
                    }
                )
                .call(Banner001)  # 调用用例
                .teardown_hook("${teardown_clean_data()}")  # 测试后置
                # 变量_局部变量:导出某个值,供下面的步骤使用。这个值来自于本条用例响应内容with_jmespath()
                .export("xx")
            ),
            Step(RunTestCase("前置2:获取banner页第一行数据ID").call(Banner003).export("id")),
            Step(
                RunRequest("步骤1:关闭 banner ")
                .with_variables(**{"xx": "as"})
                # hook_测试前:测试前的清理操作
                .setup_hook("${setup_clean_data1()}")
                .setup_hook("${setup_clean_data2()}")
                .setup_hook("${setup_clean_data3()}")
                .post(
                    "/xxx-app/xxx/operaxxx"
                )
                .with_headers(
                    **{
                        "accept-language": "${read_ini_config(Header, accept-language)}",
                        "autel-token": "${get_login_info(expert_001, token)}",
                    }
                )
                # 变量_引用:使用 ${id} 或者 $id,一般使用 ${id}
                .with_json({"id": "$id", "displayStatus": False})
                # hook_测试后:测试数据清理
                .teardown_hook("${teardown_clean_data4()}")
                .teardown_hook("${teardown_clean_data5()}")
                # 变量_局部变量:提取响应的参数值
                .extract()
                .with_jmespath("body.code", "code")
                # 校验
                .validate()
                .assert_equal('headers."Content-Type"', "application/json")
                .assert_equal("status_code", 200)
                .assert_equal("body.code", "200")
                .assert_equal("body.message", "success")
                .assert_contains("body.data.records[0].name", "接口自动化")
            ),
        ]
    
    
    
    
    if __name__ == "__main__":
        TestCaseTest002Banner().test_start()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104

    4、完整 yaml 格式的测试用例

    config:
      name: "demo with complex mechanisms"
      verify: False
      base_url: "https://postman-echo.com"
      headers:
        X-Request-Timestamp: "165460624942"
      parameters:
        user_agent: [ "iOS/10.1", "iOS/10.2" ]
        username-password: ${parameterize($file)}
      parameters_setting:
        strategies:
          user_agent:
            name: "user-identity"
            pick_order: "sequential"
          username-password:
            name: "user-info"
            pick_order: "random"
        limit: 6
      think_time:
        strategy: random_percentage
        setting:
          max_percentage: 1.5
          min_percentage: 1
        limit: 4
      variables:
        app_version: v1
        user_agent: iOS/10.3
        file: examples/hrp/account.csv
      websocket:
        reconnection_times: 5
        reconnection_interval: 2000
      export: ["app_version"]
      weight: 10
    
    teststeps:
      -
        name: get with params
        variables:
          foo1: ${ENV(USERNAME)}
          foo2: bar21
          sum_v: "${sum_two_int(1, 2)}"
        request:
          method: GET
          url: $base_url/get
          params:
            foo1: $foo1
            foo2: $foo2
            sum_v: $sum_v
        extract:
          foo3: "body.args.foo2"
        validate:
          - eq: ["status_code", 200]
          - eq: ["body.args.foo1", "debugtalk"]
          - eq: ["body.args.sum_v", "3"]
          - eq: ["body.args.foo2", "bar21"]
      -
        name: post raw text
        variables:
          foo1: "bar12"
          foo3: "bar32"
        request:
          method: POST
          url: $base_url/post
          headers:
            Content-Type: "text/plain"
          body: "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: $base_url/post
          headers:
            Content-Type: "application/x-www-form-urlencoded"
          body: "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"]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84

    5、编写gotest测试用例

    暂不投入

    6、编写json测试用例

    暂不投入

  • 相关阅读:
    推荐系统三十六式学习笔记:原理篇.模型融合13|经典模型融合办法:线性模型和树模型的组合拳
    vue2 在 template 中使用 sass 变量
    生成式人工智能(AIGC):开发者的得力助手还是职业威胁?
    【Vue组件化编程】
    .ipynb文件普盲与打开
    左移运算符重载
    运行jupyter lab时遇到代码变蓝并且无法运行的问题
    RIP 路由 3 个定时器的工作流程和 4 种防环方法
    阿里云SQL优化挑战赛实战-190毫秒干到2毫秒
    9-Dubbo架构设计与底层原理-集群容错之 Directory
  • 原文地址:https://blog.csdn.net/weixin_45451320/article/details/125530443