1. PACT 简介

1. PACT 简介

1.1. PACT 工作过程

重要

我们应谨记以下原则:

  1. 消费端编写契约时,必须依据API设计文档为准,而不是服务端的返回数据
  2. 契约文件应上传至服务器,并保持正确的版本号

../_images/87562e722ecba2b4103a05c67bd8bcd952c2c475b9c951b155f6c9213be53270.svg

1.2. 名词解释

消费端

即调用API的使用端,包括前后端分离的前端,或者调用另一个微服务的服务。

消费端本身应该是需要编写单元测试来保障自己的代码正确,此时如果需要调用服务提供端的响应,则可通过 PACT 模拟生成 Mock 服务。

PACT 此时将记录消费端所发送的数据及期望的返回,并生成契约文件,这是一个 JSON 文件。当然,契约文件也是可以人工编写的。

这是一举两得之事,在单元测试过程中,自然而然产生了契约。

桩服务

PACTMock 服务是用于在消费端单元测试时,监听发送数据和回应期望数据的服务。 如果我们需要进行前端的集成测试,此时仍然需要模拟服务提供端返回数据,则可以使用桩服务。

因此,桩服务本身,是我们日常提到的 Mock 服务,但由于在 PACT 上下文中, Mock 服务已经另有其他含义,因此改为 Stub (桩)服务。

服务器

PACT 的契约可以上传到 Broker 服务器,但这是一个可选项。

Broker 服务器让服务消费端和服务提供端保持一定程度的解耦,从服务器上可以看到不同的消费端, 对于同一个服务提供端的关联,可以帮助我们确保一个服务提供端针对的所有消费端,都已经通过检验。

1.3. 实战过程

我们以 Python 为消费端为例,描述 PACT 的实战使用过程。

扫描二维码关注公众号,回复: 5461720 查看本文章

安装开发依赖

pip3 install pact-python --user
export PATH=$PATH:~/Library/Python/3.7/bin

安装执行文件

请访问 独立安装包下载页面 ,以获取特定操作系统的独立安装包,下载并安装。

export PATH=$PATH:~/Library/Pact/bin

编写单元测试

假定该单元测试的文件名为 app-mlcproxy.py

import atexit, unittest
from pact import Consumer, Provider, Like, EachLike, Term from pact.matchers import get_generated_values import requests pact = Consumer('app').has_pact_with(Provider('mlcproxy'), host_name='localhost', port=5431, pact_dir='./pacts') pact.start_service() atexit.register(pact.stop_service) def user(): return { 'uid': '122112221', 'name': '苏渝', 'mobile_phone': '18980472890', 'idticket_id': '510108196507212137', 'payment_channel': '11', 'pay_id': '112kakak12222', 'auth_code': '122211' } def expected_ok(uid): return { 'code': 'SUCCESS', 'msg': '成功', 'result_list': [ { 'result': '01', 'uid': uid } ] } def expected_fail(uid): return { 'code': 'FAIL', 'msg': '失败', 'result_list': [ { 'result': '02', 'uid': uid } ] } def json_header(): return { 'Content-Type': 'application/json' } class UsersContract(unittest.TestCase): def test_update(self): body = user() body['userpush_type'] = '02' ok = expected_ok(body['uid']) fail = expected_fail(body['uid']) body_ok = body.copy() body_ok['idticket_id'] = '610425197608030318' body_idcard17 = body.copy() body_idcard17['idticket_id'] = '61042519760803031' # 身份证差一位 body_idcard_wrong = body.copy() body_idcard_wrong['idticket_id'] = '61042519760803031X' # 身份证检校验码不正确 (pact .given('success') .upon_receiving('更新用户') .with_request('post', '/users', body=body_ok, headers=json_header()) .will_respond_with(200, body=ok) .given('fail') .upon_receiving('身份证号码不全') .with_request('post', '/users', body=body_idcard17, headers=json_header()) .will_respond_with(500, body=fail) .given('fail') .upon_receiving('身份证验证码不正确') .with_request('post', '/users', body=body_idcard_wrong, headers=json_header()) .will_respond_with(500, body=fail)) with pact: result_ok = requests.post('http://localhost:5431/users', headers=json_header(), json=body_ok) result_idcard17 = requests.post('http://localhost:5431/users', headers=json_header(), json=body_idcard17) result_idcard_wrong = requests.post('http://localhost:5431/users', headers=json_header(), json=body_idcard_wrong) self.assertEqual(result_ok.json(), ok) self.assertEqual(result_idcard17.json(), fail) self.assertEqual(result_idcard_wrong.json(), fail) if __name__ == '__main__': unittest.main() 

完成契约测试

生成契约文件

python3 app-mlcproxy.py 

如果执行成功,在 pacts 目录下,会生成 app-mlcproxy.json 的契约文件。

发布契约文件到服务器

pact-broker publish ./pacts/app-mlcproxy.json -a 0.1 -b http://pxzx.gugud.com:5480 

其中:

  • 0.1 是版本号
  • http://pxzx.gugud.com:5480Broker 服务器的地址

发布结果是形如以下 url 格式的契约发布地址,可供服务提供端测试使用。

http://pxzx.gugud.com:5480/pacts/provider/mlcproxy/consumer/app/latest 

测试提供端是否符合契约规定

pact-provider-verifier \
  http://pxzx.gugud.com:5480/pacts/provider/mlcproxy/consumer/app/latest \ -h http://127.0.0.1:58881 \ --pact-broker-base-url=http://pxzx.gugud.com:5480 \ -r \ -a 0.1 

其中的参数说明:

  • -r 表示将发布检查结果到服务器,以大家随时可查
  • -a 0.1 指提供端的版本号
  • -h … 是指向发布的服务提供端地址,即测试的 API 地址

查看提供端是否可以发布

pact-broker can-i-deploy -a mlcproxy -b http://pxzx.gugud.com:5480 -e 0.1 

其中的参数说明:

  • -a … 要检查的服务提供端名称
  • -e 0.1 要检查的服务提供端版本

猜你喜欢

转载自www.cnblogs.com/jason89/p/10494065.html