契约测试Pact(四)
如何设计契约测试
常见的契约测试工具
Pact
python版本 pact-python
Pacto
Sprint Cloud Contract
Pact是最常用的契约测试工具
Pact基本工作流程
基于消费者的业务逻辑,生成契约文件
写代码主要写获取Pact文件(图一)的代码
模拟消费者向生产者发请求有相应的工具直接运行
Pact-Python安装
进入github
https://github.com/pact-foundation/pact-python/
用命令行安装
pip install 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
测试结果通过,如下图: