在接口自动化测试中,如何利用Pytest + JSONPath 进行接口响应断言

之前有一篇文章,介绍了如何使用JSONSchema对接口响应进行断言,主要的适用场景是对响应的数据结构进行校验,保证客户端收到的数据结构稳定和合法。今天,介绍使用JSONPath对接口响应的值进行断言方法。

上一篇文章《在接口自动化测试中,如何利用Pytest + JSON Schema 进行接口响应断言》中,介绍了JSON Schema校验接口响应的数据结构的方法。在实际的测试工作中,很多时候是需要对接口的响应数值进行校验的。这时候就不能利用JSON Schema进行校验了,需要借助JSONPath表达式从JSON中抽取数值,进行断言。

通过JSONPath表达式,使得从多层嵌套JSON数据中提取数据变得非常简单。

下面这段数据是从JsonPath的官网https://goessner.net/articles/JsonPath/上摘抄的,假定这是一个接口的response。

{ "store": {
    "book": [ 
      { "category": "reference",
        "author": "Nigel Rees",
        "title": "Sayings of the Century",
        "price": 8.95
      },
      { "category": "fiction",
        "author": "Evelyn Waugh",
        "title": "Sword of Honour",
        "price": 12.99
      },
      { "category": "fiction",
        "author": "Herman Melville",
        "title": "Moby Dick",
        "isbn": "0-553-21311-3",
        "price": 8.99
      },
      { "category": "fiction",
        "author": "J. R. R. Tolkien",
        "title": "The Lord of the Rings",
        "isbn": "0-395-19395-8",
        "price": 22.99
      }
    ],
    "bicycle": {
      "color": "red",
      "price": 19.95
    }
  },
  "expensive": 10
}

从这个response中,提取所有商品的价格,放到一个列表中,如果使用JSONPath表达式,只需要一行代码:

$.store..price

代 表 J S O N 对 象 的 根 节 点 , 代表JSON对象的根节点, JSON.store表示根节点下面的store属性,$.store…price则表示根节点下面的store属性下面的所有price属性的值。两个点表示store下面递归查找所有的price属性,因此在这个例子中可以查到所有的book的price和bicycle的price。

一个更简单的办法是从根节点开始递归查找price:

$..price

如果不使用JSONPath,想要获得所有的商品价格,则要写一个循环来读取,可以看出,使用JSONPath从JSON中提取数据变得简单和高效。

接下来看看JSONPath中都有哪些表达式。

01 — JSONPath表达式

JSONPath通过表达式定位JSON中的数据,一共有15个表达式,通过它们的灵活组合,提取JSON中数据非常容易。我们把JSON对象中每一个key都叫做一个属性(property)。下表是所有的JSONPath表达式,及其含义。
在接口自动化测试中,如何利用Pytest + JSONPath 进行接口响应断言_第1张图片
以response这个JSON对象为例,通过上面这些表达式的组合来取得值:

表达式 取得的值
$.store.* response的store属性下的所有对象,是个list,第1个元素book,是一个list,第2个元素是bicycle,是一个对象。
$.store.bicycle.color response的store属性下bicycle属性的color属性的值,red
$.store..price$..price response中所有的price属性的值: [8.95, 8.99, 22.99, 19.95]
$.store.book[*] $..book[*] response中所有的book对象,是个list
$…book[*].title response中所有的book对象的title的list:[Sayings of the Century,Moby Dick,The Lord of the Rings]
$…book[0] response中的第一本书,也是个list:[ { “category”:“reference”, “author”:“Nigel Rees”, “title”:“Sayings of the Century”, “price”:8.95 } ]
$…book[0].title response中的第1本书的title:“Sayings of the Century”
$..book[0,1].title $..book[:2].title response中的前2本书的title:[Sayings of the Century, Moby Dick]
$…book[::2].title response中每一个取一本图书的title
$..book[-1:].title $..book[(@.length-1)].title response最后1本书的title,是个list:[The Lord of the Rings]
$…book[?(@.author==‘J.R.R. Tolkien’)].title 过滤表达式,作者为’J.R.R. Tolkien’的book的书名
$…[?(@.isbn)] 过滤表达式,所有包含isbn这个属性的对象
$…[?([email protected])] 过滤表达式,所有不包含isbn这个属性的对象
$…book[?(@.price < 10)] 价格低于10的书,是一个对象list
$..book[?(@.price > $.expensive)] 价格比$.expensive高的书,是个list
$..book[?(@.author =~ /.*Tolkien/i)] 作者的名字以Tolkien结尾的书,是个list,大小写敏感
$..book[?(@.category == 'fiction' || @.category == 'reference')] category为fiction或者reference的书,是个list

通过上面的例子,可以看到还是挺简单的。

02 — 在断言中的应用

依然假定上面的JSON对象是某个接口的response反序列化得到的。接下来,看看在自动化测试中如何利用JSONPath表达式进行断言。

在Python语言中,使用JSONPath需要安装一个第三方库jsonpath。

pip install jsonpath

测试用例1:

验证response中包含’Nigel Rees’, ‘Evelyn Waugh’, ‘Herman Melville’, 'J. R. R. Tolkien’这四位作者的图书。

import jsonpath
def test_authors():
    author_list = jsonpath.jsonpath(response, '$.store.book[*].author')
    assert author_list == ['Nigel Rees', 'Evelyn Waugh', 'Herman Melville', 'J. R. R. Tolkien']
2. 测试用例2:

验证response中的商品价格包含8.95, 12.99, 8.99, 22.99, 19.95这5种。

def test_all_price():
    store_price_list = jsonpath.jsonpath(response, '$.store..price')
    # store_price_list = jsonpath.jsonpath(response, '$..price')
    assert store_price_list == [8.95, 12.99, 8.99, 22.99, 19.95]
3.测试用例3:

验证response中的第3本图书的书名是Moby Dick。

def test_third_book_title():
    book_3 = jsonpath.jsonpath(response, '$.store.book[2]')
    assert book_3[0]['title'] == "Moby Dick"
4.测试用例4:

验证response中的最后一本图书的isbn是0-395-19395-8。

def test_last_book_isbn():
    last_book_isbn = jsonpath.jsonpath(response, f'$.store.book[-1:].isbn')
    # last_book_isbn = jsonpath.jsonpath(response, f'$.store.book[(@.length-1)].isbn')
    assert last_book_isbn == "0-395-19395-8"
5.测试用例5:

验证repsonse中前两本书价格之和是8.95 + 12.99

def test_12_books_price():
    book_12 = jsonpath.jsonpath(response, '$..book[0,1].price')
    assert book_12[0] + book_12[1] == 8.95 + 12.99
6.测试用例6:

验证response中有两本书的价格小于10

def test_2books_cheap_than_10():
    book_lg10 = jsonpath.jsonpath(response, '$..book[?(@.price<10)]')
    assert len(book_lg10) <= 2
7.测试用例7:

验证response中具有color属性的商品,其color是red

def test_has_color():
    colorful_goods = jsonpath.jsonpath(response, '$.store..[?(@.color)]')
    assert "red" == colorful_goods[0]['color']

好了就举这些例子吧。更多的例子大家可以参考第一小节JSONPath表达式来尝试。

Python还有一个包叫jsonpath2,用法和jsonpath差不多。大家可以自行尝试,示例代码可以参考:

https://jsonpath2.readthedocs.io/en/latest/_modules/bookstore_test.html#TestBookStore

03 — 总结

本文介绍了JSONPath表达式语法,以及在自动化测试中的应用。使用JSONPath表达式提取JSON数据的数值,非常简介和易懂。推荐大家需要对JSON数据的准确性进行校验时,使用JSONPath表达式。

参考资料

https://goessner.net/articles/JsonPath/
https://www.cnblogs.com/angle6-liu/p/10580792.html
https://support.smartbear.com/alertsite/docs/monitors/api/endpoint/jsonpath.html
https://jsonpath2.readthedocs.io/en/latest/_modules/bookstore_test.html#TestBookStore

你可能感兴趣的:(pytest单元测试框架,python,接口测试断言)