之前我们了解了config里的各项参数,今天来了解另一个重要部分——teststeps,在这之前,先看看测试用例的分层模型。
一个testcase里(就是一个pytest格式的Python文件)可以有一个或者多个测试步骤,就是teststeps[]列表里的Step。
我的理解每一个Step就可以类比成pytest框架下的def test_xxx()的用例函数,在Step里通常都会要请求API完成测试,也可以调用其他测试用例来完成更多的需求。
可以来看下官方的测试用例逻辑图(2.x版本不同,3.x弃用了2.x的API概念):
可以看到,testsuite包含了testcase,testcase1需要依赖testcase2才可以完成,那么就可以在teststep12对其进行引用;而testcase2又依赖于testcase3,那么也可以在teststep22进行引用。
但是在整个testsuite下,这3个testcase都是相互独立的,可以独自运行。如果需要相互调用,则是在testcase内部去完成处理。
可能看起来有点绕,其实官方想表达的就是测试用例分层的一个思想:
其实这一点,在我们自己使用pytest框架编写测试用例的时候同样贯彻到了。为了自动化测试的稳定性和可维护性,每个测试用例之间相互独立是非常有必要的。
先上一段Step的代码,结合下面的点对照着看:
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") ),
从上面的代码可以看出,RunRequest的作用就是在测试步骤中请求API,并且可以对于API的响应结果进行提取、断言。
RunRequest的参数名用于指定teststep名称,它将显示在执行日志和测试报告中。
用于存放变量,但是这里的是Step步骤里的变量,不同的Step的变量是相互独立的。所以对于多个Step都要使用的变量,我们可以放到config的变量里去。
另外,如果config和Step里有重名的变量,那么当你引用这个变量的时候,Step变量会覆盖config变量。
这里就是指定请求API的方法了,常用的get、post等等。如图所示,就是用的get方法,括号里的url就是要请求的地址了。
这里要注意的是,如果在config里设置了基础url,那么步骤里的url就只能设置相对路径了。
这个就简单了,测接口不都得要传参么,对于params类型的传参,就放这就行了,key-value键值对的形式。对于body形式的传参,看后面。
同样,有header要带上的就放这里。
需要带cookie的,可以用.with_cookies方法。
对于body类型的传参,可以用.with_data。
如果是json类型的body请求体,可以用.with_json。
这里就是要做提取操作了,使用.with_jmespath(jmes_path: Text, var_name: Text)。
这里是采用了JMESPath语言,JMESPath是JSON的查询语言,可以便捷的提取json中你需要的元素。
第一个参数是你的目标元素的jmespath表达式,第二个元素则是用来存放这个元素的变量,供有需要的引用。
这里不展开,后面单讲。
断言,我们测试最终就是要验证接口返回是否符合预期。
那在httprunner框架中,可以使用assert_XXX(jmes_path: Text, expected_value: Any)来进行提取和验证。
第一个参数还是jmespath表达式,第二个参数则是预期值。
assert_XXX这种方式相信用过自动化测试框架的都不会陌生,所以也非常容易上手。目前httprunner还是封装了非常丰富的断言方法的,相信可以满足绝大多数的需求了。
到这里,一个接口的请求和验证就完成了,我打算用flask快速写几个demo用的接口,可以对必要的方法更进一步的演示。