前言
众所周知,在接口测试工作中,接口之间参数的关联是再常见不过的应用,Httprunner3.x在这一块的支持上用法也是相当丰富,下面结合实例简单记录一下使用技巧
变量的提取与传递
由于Httprunner
的Step
支持两个方式。一个是RunRequest()
,即是发送一个API请求,一个是RunTestCase()
,是用例中调用另一个用例。
- 参数提取:
extract()
- 参数导出:
export()
RunRequest类型的Step
在用例步骤中如果类型是RunRequest,那么只用提取变量,不需要导出就可以向下步骤中传递变量,看例子
from httprunner import HttpRunner, Config, Step, RunRequest
from utils.FakerData import *
from api.dlvopenapi import unified_order, order_query
from utils.SigleData import FakerSingleData
class TestCaseDlvOpenApiSuccess(HttpRunner):
config = (
Config("发放成功的测试案例")
.variables(
**{
"appId": 200803014515363414,
"accountName": get_name(),
"idCard": "420624199109037552",
"amount": 0.02,
"signType":"rsa2",
"version":"1.0",
"accountNo": 6225380092315252,
"phone":get_phone(),
"serviceCompanyId": "10000032",
"key": "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAOI4fc5POr0cZmyyGuwAonQGNVUvEd8KWtYk2ozNM1S6la7BK7DwWyk6kI10/NsY+Wues+C0fN86Ol0uckTF+s4NqMqw/W8PZ0HOV0mW1Ew/EV+HT1jRnbYviTRNWx9zS+xRjiDam3VdbElSwPQQulefAlQctcxsT1nPGSbWxvFpAgMBAAECgYEAnG6iGHNTVAh6j3mOAlrh+8d7Q9+bxRd8/w5XDvyrHVE1RrYPx3g+IcF8ykT2wW+Asrn4+07z9s1mJJ+EpygcqOmWtrExQlHjYcAn+27usxhTjWtNZ7AQoF0O0zIIAb8H2dm6Sin2fwvkZORaUy9gMlM7FW/LA48l49ptvs4aTZ0CQQDx5ezsesL8zA3SR+lr8xLTSjJokUOrK5wbYj+SGe+jgkUDxNU53zQXjTKM99rR+4cwomKbMFqGhZzDw1rEmccrAkEA72iYnXAKFHX05TB8YNkcxouwkFpi3rcD7m8LjEcXT/quNvsrcHfJB4iw63H2TwXvUQ4SJrxzjUMwSNkB19zfuwJBAOu6/0ns0Dv+trFndufF92CEe98/QMx8MSLWedDtCYU0HAFyPcCp7V/OL6cEmu/qyHHyrVlCo9VYO87if3/7xAUCQBi98Y/LxW7p5d5NzXzg00V9qEiy3qbvuRtKJKJhsnoUiS6rdIjSCFeb+9TJWVA/Z8UztBKGxVZjDDlrG/KoJAMCQQCRnIyn35lHhj5iXyB2Ofo5wHI45NvPpj7ut3rec58fMLTs3yw5w9OWnOSUCnbZ3gTQHeu4/3Ebu4ozzw4bi2iK"
}
)
.base_url("http://192.168.1.92:11958")
.verify(False)
.export( *["reqNo", "outOrderNo"])
)
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)
),
Step(
RunRequest("发放订单查询")
.setup_hook('${setup_request($request,$key)}')
.with_variables(**{
"method": "ayg.salary.payQuery",
"nonce": get_nonce(),
"timestamp": get_current_time(),
})
.post(order_query.OrderQueryApi.path)
.with_json(order_query.OrderQueryApi.json)
.validate()
.assert_equal("status_code", 200)
.assert_equal("body.code", "0000")
.assert_equal("body.data.code", "30")
.assert_equal("body.data.msg", "支付成功")
)
]
if __name__ == "__main__":
TestCaseDlvOpenApiSuccess().test_start()
如上例子:
-
在
Step1
中通过extract()
提取了两个变量,分别是reqNo
,outOrderNo
,此时是不需要声明方法export()
导出的。.extract() .with_jmespath("body.data.reqNo", "reqNo") .with_jmespath("body.data.outOrderNo", "outOrderNo")
在
Step2
中直接通过$reqNo
,$outOrderNo
引用导出的变量,即可完成参数的传递和关联
RunTestCae类型的Step
在一个测试用例中的步骤中如果调用了另一个测试用例,则需要手动导出变量,导出变量的方式两种,
- 在被调用用例的全局Config中导出
- 在调用用例的时候的步骤中导出
看例子
- 被调用的Login用例
from api.common.login import Login
from httprunner import HttpRunner, Config, Step, RunRequest
class TestProviderLogin(HttpRunner):
config = (
Config("admin端登录成功")
.base_url("https://p-test92.aiyuangong.com")
.variables(**{
"loginName": "console-provider",
"password": "123456"
})
.verify(False)
.export(*["userid","access_token"])
)
teststeps = [
Step(
RunRequest("登录请求")
.post(Login.path).with_json(Login.json)
.extract()
.with_jmespath("body.data.userProfiles[0].id", "userid")
.with_jmespath("body.data.access_token", "access_token")
.validate()
.assert_equal("body.code", 200)
)
]
if __name__ == '__main__':
TestProviderLogin().test_start()
-
变量的提取和导出分两个步骤,先提取
.extract() .with_jmespath("body.data.userProfiles[0].id", "userid") .with_jmespath("body.data.access_token", "access_token")
再导出
Config("admin端登录成功") .base_url("https://p-test92.aiyuangong.com") .variables(**{ "loginName": "console-provider", "password": "123456" }) .verify(False) .export(*["userid","access_token"])
如果在此处导出了变量,那么在后续引用到该用例的用例的中,就不需要再在调用后导出了
如果选择在此用例中只提取,不导出,在用例调用的时候就必须进行导出操作
from httprunner import HttpRunner, RunRequest, RunTestCase,Step, Config
from api.common.login import Login
from api.common.upload import Upload
from testcases.common.p_login_success_test import TestProviderLogin
class TestUploadFileAndGetDownloadCode(HttpRunner):
config = (
Config("上传文件获取downloadcode")
.base_url("https://p-test92.aiyuangong.com")
.variables(**{
"loginName": "console-provider",
"password": "123456",
"fileName_": "pkq.jpeg",
"file_": "file/pkq.jpeg"
})
)
teststeps = [
Step(
RunTestCase("登录后获取token")
.call(TestProviderLogin)
.export(*["userid","access_token"])
),
Step(
RunRequest("上传文件")
.post(Upload.path)
.with_headers(**{
"Cookie": "x - sec - profile =$userid;AYG_SESSIONID =$access_token"
})
.upload(**Upload.file)
.extract()
.with_jmespath("body.data.downloadCode","downloadCode")
.with_jmespath("body.data.fileName","fileName")
.with_jmespath("body.data.referID","referID")
.validate()
.assert_equal("body.code",200)
)
]
if __name__ == '__main__':
TestUploadFileAndGetDownloadCode().test_start()
如上,Step1
中调用了Login
用例,而后进行了导出操作.export(*["userid","access_token"])
,在Step2
中就进行变量的关联传递了
思考一下
两个地方的导出最佳实践是什么?
- 如果在被调用用例的
Config
中进行了变量的导出,那么会把导出的变量加入所有调用此用例的执行会话上下文中,无论调用方用不用得到, - 如果在被调用用例里只是提取了所有调用他的用例中可能用到的参数,在调用方用例中调用完用例以后按需导出此用例用得到的变量,那么只会在调用方用例中的执行会话上下文中加入此时导出的变量,而不会加入无用变量。