在API的自动化测试维度中,测试维度分为两个维度,一个是单独的对API的验证,客户端发送一个请求后,服务端得到客户端的请求并且响应回复给客户端;
另外一个维度是基于业务场景的测试,基于业务场景的也就是说编编写的API的测试用例是基于产品的业务逻辑。
抛开两个维度的思考点,作为测试团队的工作内容,首先要保障产品的业务逻辑是可以使用的,只要这样,产品才能够给客户带来价值,
在基本的业务逻辑稳定的基础上,再一步需要思考的是整个系统的稳定性,抗压性和系统的承载负载的能力。
那么在工程效率的角度上来思考,使用代码或者工具都不是核心,核心是如何使用这些工具或者代码来提升测试的效率,
优化研发的流程,并持续的改进,从而达到过程中的改进。不管工具还是代码,对产品完整性的测试,
都要考虑产品的业务逻辑,也就是产品的场景,而如何通过API的自动化测试方式来达到产品的业务场景的测试。
如下的案例代码业务为依据接口可以获取到所有的书籍信息,可以创建数据,查看某一本书的信息,修改它的信息和删除书籍,案例代码为:
1 #!/usr/bin/env python 2 # -*-coding:utf-8 -*- 3 from flask import Flask,redirect,render_template,url_for,request,jsonify,abort,make_response 4 from flask_restful import Resource,Api 5 from flask_httpauth import HTTPBasicAuth 6 7 8 app=Flask(__name__) 9 api=Api(app=app) 10 11 auth=HTTPBasicAuth() 12 13 @auth.get_password 14 def get_password(name): 15 if name==\'wuya\': 16 return \'admin\' 17 @auth.error_handler 18 def authorized(): 19 return make_response(jsonify({\'error\':\'请认证\'}),401) 20 21 22 books=[ 23 { 24 \'id\':1, 25 \'author\':\'无涯\', 26 \'name\':\'Python自动化测试实战\', 27 "done":True 28 }, 29 { 30 \'id\': 2, 31 "aurhor":"无涯", 32 \'name\': \'Python测试开发实战\', 33 "done":False 34 } 35 ] 36 37 class BooksApi(Resource): 38 def get(self): 39 return jsonify(books) 40 41 def post(self): 42 if not request.json or not \'author\' in request.json: 43 abort(400) 44 book={ 45 \'id\': books[-1][\'id\'] + 1, 46 # \'author\':request.json[\'author\'], 47 \'author\': request.json.get(\'author\'), 48 \'name\': request.json.get(\'name\'), 49 \'done\': False 50 } 51 books.append(book) 52 return jsonify({"status":0,\'msg\':\'创建书籍成功\',\'datas\':book}) 53 54 class BookApi(Resource): 55 def get(self,book_id): 56 book=list(filter(lambda t:t[\'id\']==book_id,books)) 57 if len(book)==0: 58 abort(400) 59 else: 60 return jsonify({\'status\':0,\'msg\':\'ok\',\'datas\':book}) 61 62 def put(self,book_id): 63 book=list(filter(lambda t:t[\'id\']==book_id,books)) 64 if len(book)==0: 65 abort(404) 66 elif not request.json: 67 abort(400) 68 elif \'author\' not in request.json: 69 abort(400) 70 elif \'done\' not in request.json and type(request.json[\'done\']) is not bool: 71 abort(400) 72 book[0][\'author\']=request.json.get(\'author\',book[0][\'author\']) 73 book[0][\'name\'] = request.json.get(\'name\', book[0][\'name\']) 74 book[0][\'done\'] = request.json.get(\'done\', book[0][\'done\']) 75 return jsonify({\'status\':0,\'msg\':\'修改成功\',\'datas\':book}) 76 77 def delete(self,book_id): 78 book = list(filter(lambda t: t[\'id\'] == book_id, books)) 79 if len(book)==0: 80 abort(404) 81 books.remove(book[0]) 82 return jsonify({\'status\':1001,\'msg\':\'删除成功\'}) 83 84 api.add_resource(BooksApi,\'/v1/api/books\',endpoint=\'/v1/api/books\') 85 api.add_resource(BookApi,\'/v1/api/book/<int:book_id>\') 86 87 if __name__ == \'__main__\': 88 app.run(debug=True)
依据上面的信息,涉及到的测试点非常多,但是主要可以考虑这么几点,分别是创建书籍信息,查看创建的书籍信息,对创建的书籍信息进行修改,和最后删除创建的书籍信息,
那么编写这样的API测试用例的编写,也可以从两个维度思考,第一个维度是基于业务场景,也就是说编写的API测试使例它是有顺序的,分别是创建,查看,修改,和删除,见API的测试代码:
1 #!/usr/bin/python3 2 #coding:utf-8 3 import pytest 4 import requests 5 6 7 def writeBook(bookID): 8 with open(\'bookID\',\'w\') as f: 9 f.write(bookID) 10 11 def readBookID(): 12 with open(\'bookID\',\'r\') as f: 13 return int(f.read()) 14 15 def test_001_addBook(): 16 \'\'\'创建书籍\'\'\' 17 dict1={"author":"无涯","name":"Python自动化测试实战","done":True} 18 r=requests.post( 19 url=\'http://127.0.0.1:5000/v1/api/books\', 20 json=dict1) 21 writeBook(str(r.json()[\'datas\'][\'id\'])) 22 assert r.json()[\'datas\'][\'author\']==\'无涯\' 23 def test_002_queryBook(): 24 \'\'\'查看创建的书籍信息\'\'\' 25 r=requests.get( 26 url=\'http://127.0.0.1:5000/v1/api/book/{0}\'.format(readBookID())) 27 assert r.json()[\'datas\'][0][\'id\']==readBookID() 28 29 30 def test_003_setBook(): 31 \'\'\'修改书籍信息\'\'\' 32 dict1 = {"author": "无涯课堂", "name": "Python自动化测试实战", "done": True} 33 r=requests.put( 34 url=\'http://127.0.0.1:5000/v1/api/book/{0}\'.format(readBookID()), 35 json=dict1) 36 assert r.json()[\'datas\'][0][\'author\']==\'无涯课堂\' 37 def test_004_delBook(): 38 \'\'\'删除书籍信息\'\'\' 39 r=requests.delete( 40 url=\'http://127.0.0.1:5000/v1/api/book/{0}\'.format(readBookID())) 41 assert r.json()[\'status\']==1001
查看如上的测试代码后,可以看到刚才说的测试场景都已包含进去。
依据执行后输出的结果信息,可以看到它是按我们设计的顺序的,这样的测试点符合我们的设计思路,
但是存在的缺点也是,比如业务逻辑发生变化,可以批量添加课程,那么这个测试点应该放在哪里了?
按照之前的设计思路,只能放在第二位,因为测试用例它是按顺序执行的,很显然它会打乱已经有的执行顺序,
当然对链路很长的测试点来说,这样写也没什么错误。
下面再看另外一种思路,就是测试用例之间是没有顺序的,这样就可以很好的解决上面说的,
批量增加,批量修改或者批量删除也好,测试点是无顺序的,所以增加或者建=减少测试点,也是无所谓的。
修改后的测试点见如下:
1 #!/usr/bin/python3 2 #coding:utf-8 3 import pytest 4 import requests 5 6 def writeBook(bookID): 7 with open(\'bookID\',\'w\') as f: 8 f.write(bookID) 9 10 def readBookID(): 11 with open(\'bookID\',\'r\') as f: 12 return int(f.read()) 13 14 def addBook(): 15 dict1={"author":"无涯","name":"Python自动化测试实战","done":True} 16 r=requests.post( 17 url=\'http://127.0.0.1:5000/v1/api/books\', 18 json=dict1) 19 writeBook(str(r.json()[\'datas\'][\'id\'])) 20 return r 21 22 def queryBook(): 23 r=requests.get( 24 url=\'http://127.0.0.1:5000/v1/api/book/{0}\'.format(readBookID())) 25 return r 26 27 def setBook(): 28 dict1 = {"author": "无涯课堂", "name": "Python自动化测试实战", "done": True} 29 r=requests.put( 30 url=\'http://127.0.0.1:5000/v1/api/book/{0}\'.format(readBookID()), 31 json=dict1) 32 return r 33 34 def delBook(): 35 r=requests.delete( 36 url=\'http://127.0.0.1:5000/v1/api/book/{0}\'.format(readBookID())) 37 return r 38 39 40 def test_addBook(): 41 \'\'\'创建书籍\'\'\' 42 r=addBook() 43 delBook() 44 assert r.json()[\'datas\'][\'author\']==\'无涯\' 45 def test_queryBook(): 46 \'\'\'查看创建的书籍信息\'\'\' 47 addBook() 48 r=queryBook() 49 delBook() 50 assert r.json()[\'datas\'][0][\'id\']==readBookID() 51 52 def test_updateBook(): 53 \'\'\'修改书籍信息\'\'\' 54 addBook() 55 r=setBook() 56 delBook() 57 assert r.json()[\'datas\'][0][\'author\']==\'无涯课堂\' 58 def test_delBook(): 59 \'\'\'删除书籍信息\'\'\' 60 addBook() 61 r=delBook() 62 assert r.json()[\'status\']==1001
修改后的测试用例之间执行是无顺序的,我们并不在乎哪个测试点先执行,哪个后执行,
每个测试点之间都是独立的,也不互相依赖同时也是基于业务场景的测试。