HttpRunner3.X学习笔记(4)- 用例文件的 Step-RunRequest

前言:

在一个pytest格式的Python文件testcase里可以有一个或者多个测试步骤,就是teststeps[]列表里的Step()

每一个Step()就可以类比成pytest框架下的def test_xxx()的用例函数,在每一个Step里描述请求API的基本信息,用到是是RunRequest()类,当然也可以调用其他测试用例RunTestCase(),这个后面再详解。

官方的测试用例逻辑图如下(2.x版本不同,3.x弃用了2.x的API概念):


image.png

官方想表达的就是测试用例分层的一个思想:

  • 测试用例(testcase)应该是完整且独立的,每条测试用例应该是都可以独立运行的
  • 测试用例是测试步骤(teststep)的有序集合
  • 测试用例集(testsuite)是测试用例的无序集合,集合中的测试用例应该都是相互独立,不存在先后依赖关系的;如果确实存在先后依赖关系,那就需要在测试用例中完成依赖的处理

为了自动化测试的稳定性和可维护性,每个测试用例之间相互独立是非常有必要的。

teststeps-RunRequest

    teststeps = [
        Step(
            RunRequest("发放收单成功").
                setup_hook('${setup_request($request,$key)}')
                .with_variables(
                **{
                    "attach": "附件",
                    "bank": "ICBC1",
                    "batchNo": "20200801",
                    "depositBank": "工商",
                    "extInfo": "API001-商户004-攻城狮",
                    "foreignNationality": "CN",
                    "memo": "API_AUTO1",
                    "outOrderNo": get_outOrderNo(),
                    "personalIncomeTax": "0",
                    "phone": "$phone",
                    "postId": "10468",
                    "postName": "tester",
                    "serviceFee": "0",
                    "serviceType": "10002",
                    "shouldAmount": "0",
                    "totalFee": "0",
                    "nonce": get_nonce(),
                    "timestamp": get_current_time()}
            )
                .post(unified_order.UnifiedOrderApi.path)
                .with_json(unified_order.UnifiedOrderApi.json)
                .teardown_hook('${polling_assert(state_,30)}')
                .extract()
                .with_jmespath("body.data.reqNo", "reqNo")
                .with_jmespath("body.data.outOrderNo", "outOrderNo")
                .validate()
                .assert_equal("status_code", 200)
                .assert_equal("body.code", "0000")
                .assert_equal("body.msg", "处理成功")
                .assert_equal('${db_filed_states_with_parm(state_)}', 30)
                .assert_equal('${db_filed_states_with_parm(balance_state_)}', 39)
                .assert_equal('${db_filed_states_with_parm(channel_balance_state_)}', 39)


        ) ]

name:RunRequest("step name")

RunRequest的参数名用于指定Step的名称,它将显示在执行日志和测试报告中

image.png

with_variables(**{key:value...})

用于存放局部(步骤)变量,作用域是此Step,不同的Step的变量是相互独立的。所以对于多个Step都要使用的变量,我们可以放到config的变量里去。
另外,如果configStep里有重名的变量,那么当你引用这个变量的时候,Step变量会覆盖config变量。

method(url)

指定请求API的方法了,常用的getpost等等。如图所示,就是用的post方法,括号里的url参数就是要请求的地址了。
这里值得注意的是,如果在config里设置了base_url,那么步骤里的url就只能设置path部分了。
以下是支持的method类型:

    def get(self, url: Text) -> RequestWithOptionalArgs:
        self.__step_context.request = TRequest(method=MethodEnum.GET, url=url)
        return RequestWithOptionalArgs(self.__step_context)

    def post(self, url: Text) -> RequestWithOptionalArgs:
        self.__step_context.request = TRequest(method=MethodEnum.POST, url=url)
        return RequestWithOptionalArgs(self.__step_context)

    def put(self, url: Text) -> RequestWithOptionalArgs:
        self.__step_context.request = TRequest(method=MethodEnum.PUT, url=url)
        return RequestWithOptionalArgs(self.__step_context)

    def head(self, url: Text) -> RequestWithOptionalArgs:
        self.__step_context.request = TRequest(method=MethodEnum.HEAD, url=url)
        return RequestWithOptionalArgs(self.__step_context)

    def delete(self, url: Text) -> RequestWithOptionalArgs:
        self.__step_context.request = TRequest(method=MethodEnum.DELETE, url=url)
        return RequestWithOptionalArgs(self.__step_context)

    def options(self, url: Text) -> RequestWithOptionalArgs:
        self.__step_context.request = TRequest(method=MethodEnum.OPTIONS, url=url)
        return RequestWithOptionalArgs(self.__step_context)

    def patch(self, url: Text) -> RequestWithOptionalArgs:
        self.__step_context.request = TRequest(method=MethodEnum.PATCH, url=url)
        return RequestWithOptionalArgs(self.__step_context)

API参数的方法

  • with_json(**{"foo1": "$foo1", "foo2": "$foo2", "sum_v": "$sum_v"})
  • with_params(**{"foo1": "$foo1", "foo2": "$foo2", "sum_v": "$sum_v"})
  • with_data("foo1=$foo1&foo2=$foo2&foo3=$foo3")
  • with_headers(**{key:value})
  • with_cookies(**{key:value})

extract()

提取操作,后面紧跟着配合.with_jmespath(jmes_path: Text, var_name: Text)使用。这里是采用了JMESPath语言,JMESPath是JSON的查询语言,可以便捷的提取json中你需要的元素。

  • 第一个参数是你的目标元素的jmespath表达式,
  • 第二个元素则是用来存放这个元素的变量,即把从json提取出来的值赋值给一个变量
    image.png

validate()

断言,测试最终就是要验证接口返回是否符合预期。配合断言方法使用assert_xxx(jmes_path: Text, expected_value: Any)

httprunner框架中,可以使用assert_xxx(jmes_path: Text, expected_value: Any)来进行提取和验证

  • 第一个参数还是jmespath表达式
  • 第二个参数是预期值


    image.png

断言支持的类型

class StepRequestValidation(object):
    def __init__(self, step_context: TStep):
        self.__step_context = step_context

    def assert_equal(
        self, jmes_path: Text, expected_value: Any, message: Text = ""
    ) -> "StepRequestValidation":
        self.__step_context.validators.append(
            {"equal": [jmes_path, expected_value, message]}
        )
        return self

    def assert_not_equal(
        self, jmes_path: Text, expected_value: Any, message: Text = ""
    ) -> "StepRequestValidation":
        self.__step_context.validators.append(
            {"not_equal": [jmes_path, expected_value, message]}
        )
        return self

    def assert_greater_than(
        self, jmes_path: Text, expected_value: Union[int, float], message: Text = ""
    ) -> "StepRequestValidation":
        self.__step_context.validators.append(
            {"greater_than": [jmes_path, expected_value, message]}
        )
        return self

    def assert_less_than(
        self, jmes_path: Text, expected_value: Union[int, float], message: Text = ""
    ) -> "StepRequestValidation":
        self.__step_context.validators.append(
            {"less_than": [jmes_path, expected_value, message]}
        )
        return self

    def assert_greater_or_equals(
        self, jmes_path: Text, expected_value: Union[int, float], message: Text = ""
    ) -> "StepRequestValidation":
        self.__step_context.validators.append(
            {"greater_or_equals": [jmes_path, expected_value, message]}
        )
        return self

    def assert_less_or_equals(
        self, jmes_path: Text, expected_value: Union[int, float], message: Text = ""
    ) -> "StepRequestValidation":
        self.__step_context.validators.append(
            {"less_or_equals": [jmes_path, expected_value, message]}
        )
        return self

    def assert_length_equal(
        self, jmes_path: Text, expected_value: int, message: Text = ""
    ) -> "StepRequestValidation":
        self.__step_context.validators.append(
            {"length_equal": [jmes_path, expected_value, message]}
        )
        return self

    def assert_length_greater_than(
        self, jmes_path: Text, expected_value: int, message: Text = ""
    ) -> "StepRequestValidation":
        self.__step_context.validators.append(
            {"length_greater_than": [jmes_path, expected_value, message]}
        )
        return self

    def assert_length_less_than(
        self, jmes_path: Text, expected_value: int, message: Text = ""
    ) -> "StepRequestValidation":
        self.__step_context.validators.append(
            {"length_less_than": [jmes_path, expected_value, message]}
        )
        return self

    def assert_length_greater_or_equals(
        self, jmes_path: Text, expected_value: int, message: Text = ""
    ) -> "StepRequestValidation":
        self.__step_context.validators.append(
            {"length_greater_or_equals": [jmes_path, expected_value, message]}
        )
        return self

    def assert_length_less_or_equals(
        self, jmes_path: Text, expected_value: int, message: Text = ""
    ) -> "StepRequestValidation":
        self.__step_context.validators.append(
            {"length_less_or_equals": [jmes_path, expected_value, message]}
        )
        return self

    def assert_string_equals(
        self, jmes_path: Text, expected_value: Any, message: Text = ""
    ) -> "StepRequestValidation":
        self.__step_context.validators.append(
            {"string_equals": [jmes_path, expected_value, message]}
        )
        return self

    def assert_startswith(
        self, jmes_path: Text, expected_value: Text, message: Text = ""
    ) -> "StepRequestValidation":
        self.__step_context.validators.append(
            {"startswith": [jmes_path, expected_value, message]}
        )
        return self

    def assert_endswith(
        self, jmes_path: Text, expected_value: Text, message: Text = ""
    ) -> "StepRequestValidation":
        self.__step_context.validators.append(
            {"endswith": [jmes_path, expected_value, message]}
        )
        return self

    def assert_regex_match(
        self, jmes_path: Text, expected_value: Text, message: Text = ""
    ) -> "StepRequestValidation":
        self.__step_context.validators.append(
            {"regex_match": [jmes_path, expected_value, message]}
        )
        return self

    def assert_contains(
        self, jmes_path: Text, expected_value: Any, message: Text = ""
    ) -> "StepRequestValidation":
        self.__step_context.validators.append(
            {"contains": [jmes_path, expected_value, message]}
        )
        return self

    def assert_contained_by(
        self, jmes_path: Text, expected_value: Any, message: Text = ""
    ) -> "StepRequestValidation":
        self.__step_context.validators.append(
            {"contained_by": [jmes_path, expected_value, message]}
        )
        return self

    def assert_type_match(
        self, jmes_path: Text, expected_value: Any, message: Text = ""
    ) -> "StepRequestValidation":
        self.__step_context.validators.append(
            {"type_match": [jmes_path, expected_value, message]}
        )
        return self

你可能感兴趣的:(HttpRunner3.X学习笔记(4)- 用例文件的 Step-RunRequest)