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