如何設計契約測試
常見的契約測試工具
Pact
python版本pact-python
Pacto
Sprint Cloud Contract
Pact是最常用的契約測試工具
Pact基本工作流程
基於消費者的業務邏輯,生成契約文件
寫代碼主要寫獲取Pact文件(圖一)的代碼
模擬消費者向生產者發請求有相應的工具直接運行
Pact-Python安裝
進入github官網
https://github.com/pact-foundation/pact-python/
用命令行安裝
如果碰到報錯
那就是在pact\bin目錄下缺少ZIP壓縮文件
解決方案:
進如pact包下載官網,找到對應的ZIP包自行下載,放到pact\bin目錄下,再重新用命令安裝
https://github.com/pact-foundation/pact-ruby-standalone/releases
Pact 設計用例
寫一個例子
創建一個生產者和兩個消費者
miku.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>消費者 Miku</title> </head> <body> <h1 class = 'cover-heading'>{{result['name']}}</h1> <p class="lead">郵箱:{{result['contact']['Email']}}</p> <p class="lead">電話:{{result['contact']['Phone Number']}}</p> </body> </html>
nanoha.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>消費者 Miku</title> </head> <body> <h1 class = 'cover-heading'>{{result['name']}}</h1> <p class="lead">郵箱:{{result['contact']['Email']}}</p> <p class="lead">電話:{{result['contact']['Phone Number']}}</p> </body> </html>
用flask寫一個mock接口
用來當做生產者
api_service.py
#! usr/bin/env python # _*_ coding: utf-8 _*_ from flask import Flask,request,jsonify app = Flask(__name__) app.config['JSON_SORT_KEYS'] = False rsp_body = [ { "salary": 45000, "name": "Hatsune Miku", "nationality":"Japan", "contact": { "Email": "hatsune.miku@woniuxy.com", "Phone Number": "13900110001" } },{ "salary": 80000, "name": "Takamachi Nanoha", "nationality":"Japan", "contact": { "Email": "takamachi.nanoha@woniuxy.com", "Phone Number": "18800880008" } } ] @app.route('/information',methods=['GET']) def test(): get_name = request.args.get("name","").lower() if get_name == 'miku': rsp = jsonify(rsp_body[0]) elif get_name == 'nanoha': rsp = jsonify(rsp_body[1]) else: rsp = jsonify({'status': '404 not found.'}) return rsp if __name__ == '__main__': app.run(host='0.0.0.0', port=8080)
同樣用flask寫兩個消費者consumer_miku.py 和 consumer_nanoha.py
consumer_miku.py
from flask import Flask,request,jsonify,render_template import urllib3 import json app = Flask(__name__) @app.route('/miku',methods=['GET']) def miku_html(): params = {"name": "miku"} http = urllib3.PoolManager() resp = http.request('GET', 'http://localhost:8080/information', params) result = json.loads(resp.data.decode()) return render_template("miku.html", result = result) if __name__ == '__main__': app.run(host='0.0.0.0', port=8081)
consumer_nanoha.py
from flask import Flask,request,jsonify,render_template import urllib3 import json app = Flask(__name__) @app.route('/nanoha',methods=['GET']) def nanoha_html(): params = {"name": "nanoha"} http = urllib3.PoolManager() resp = http.request('GET', 'http://localhost:8080/information', params) result = json.loads(resp.data.decode()) return render_template("nanoha.html", result = result) if __name__ == '__main__': app.run(host='0.0.0.0', port=8082)
運行生產者和消費者,然后打開URL
pact-verifier --provider-base-url=http://localhost:8080 --pact-url=consumer_miku-provider.json
創建第一個Pact契約測試用例
先做一個公共方法
作用:用來實現我們一個發請求的方法
query.py
#! usr/bin/env python # -*- coding: utf-8 -*- import requests def get_cartoon_characters(name): # pact作為模擬生產者時,其端口默認為1234 resp = requests.get('http://localhost:1234/information',{'name':name}) return resp
我們做契約測試,首先是模擬生產者,'1234'是pact默認的端口號
寫一個契約測試用例
contract.py
#! usr/bin/env python # -*- coding: utf-8 -*- import atexit import unittest from pact import Consumer,Provider from microservice.Contract_test.query import get_cartoon_characters # 構造pact對象,定義消費者服務的名字並給它一個生產者服務 pact = Consumer('Consumer Miku').has_pact_with(Provider('Provider')) pact.start_service() # 注冊退出的時候關閉pact服務 atexit.register(pact.stop_service) class GetMikuInfoContract(unittest.TestCase): def test_miku(self): # 定義響應期望的結果 expected = { "salary": 45000, "name": "Hatsune Miku", "nationality": "Japan", "contact": { "Email": "hatsune.miku@woniuxy.com", "Phone Number": "13900110001" } } # 定義響應頭 headers = { "Content-Type":"application/json" } # 定義模擬生產者提供者接受請求以及響應的方式 (pact .upon_receiving('a request for Miku') .with_request( method='GET', path='/information', query={'name':'miku'} ).will_respond_with(200,headers,expected)) # 定義消費者服務向模擬生產者發出請求並活得響應 with pact: result = get_cartoon_characters('miku') # 做最后的斷言 self.assertEqual(result.json(),expected) if __name__ == '__main__': unittest.main(verbosity=2)
運行
先運行生成一個契約文件(.json文件)
先運行生產者api_service.py
打開終端,進入契約腳本目錄,運行命令
pact-verifier --provider-base-url=http://localhost:8080 --pact-url=consumer_miku-provider.json pact-verifier --provider-base-url=http://localhost:8080 --pact-url=consumer_miku-provider.json
測試結果通過,如下圖: