在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
修改后的測試用例之間執行是無順序的,我們並不在乎哪個測試點先執行,哪個后執行,
每個測試點之間都是獨立的,也不互相依賴同時也是基於業務場景的測試。