【Python】pact-python模块进行契约测试

news2024/7/30 10:15:33

Pact是一个契约测试框架,有多种语言实现,本文主要介绍模块pact-python进行契约测。
官网:https://docs.pact.io/implementation_guides/python/readme

安装命令:pip install pact-python  
安装过程中如果报错,安装失败,需要进如pact包下载官网,找到对应的ZIP包自行下载,
https://github.com/pact-foundation/pact-ruby-standalone/releases 
放到pact\bin目录下,再重新用命令pip install pact-python  安装

此外需要安装另外两个依赖包:pip install requests 和pip install Flask

Step 1: 写一个 customer:customer_success.py

import requests

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0',
    "Content-Type": "application/json",
}
data={
    "data": {
        "transactionType": "C",  # 
        "brnNo": "9998199930",   #
        "taxInvoiceNumber": "202106161221150000000001", 
        "supplierBrnNo":"9998199954",
        "creationDate": "20210616",     #
        "taxInvoiceType": "11",  # 
        "supplyPrice": 75000000000,     #
        "taxAmount": 320000000,         # 
        "buyerBrnNo": "9998199916",
        # 非必填
        "mainItems": "전산장비",
        "remark1": "하드웨어 10종",
        "remark2": "소프트웨어 30종",
        "supplierCmpName": "서울데이터시스템",
        "buyerCmpName": "종각은행"

    },
    "header": {
        "chanlId": "IDC",
        "grpId": "GROUPID001",
        "messageTimeStamp": '2021-05-17T20:00:20.123Z',
        "trackingId": "ABC123DEF456"
    }
}
url = 'http://127.0.0.1:8080'


def OLTP_inquiry():
    api = '/api/v2/coperator/taxInvoice'
    f_url = url + api
    print("请求接口:",f_url)
    json_data = data
    print("请求参数:",json_data)
    resp = requests.post(f_url, json=json_data,headers=headers)
    print("响应参数:",resp.json())


if __name__ == '__main__':
    OLTP_inquiry()


Step 2: 写一个 customer:customer_error.py

import requests

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0',
    "Content-Type": "application/json",
}
data={
    "data": {
        "transactionType": "C",  # C-create,目前只支持C
        "brnNo": "9998199930",   # BRN
        "taxInvoiceNumber": "202106161221150000000000",  # BRN
        "supplierBrnNo":"9998199954",
        "creationDate": "20210616",     #
        "taxInvoiceType": "11",  # 11-Electronic Tax Invoice,21-Electronic Tax Invoice(Exempt from taxation),31-Electronic Tax Invoice(Customs)
        "supplyPrice": 75000000000,     # Supply Price in KRW
        "taxAmount": 320000000,         # Tax Amount in KRW
        "buyerBrnNo": "9998199916",
        # 非必填
        "mainItems": "전산장비",
        "remark1": "하드웨어 10종",
        "remark2": "소프트웨어 30종",
        "supplierCmpName": "서울데이터시스템",
        "buyerCmpName": "종각은행"

    },
    "header": {
        "chanlId": "IDC",
        "grpId": "GROUPID001",
        "messageTimeStamp": '2021-05-17T20:00:20.123Z',
        "trackingId": "ABC123DEF456"
    }
}
url = 'http://127.0.0.1:8080'

def OLTP_inquiry_error():
    api = '/api/v2/coperator/taxInvoice'
    f_url = url + api
    print("请求接口:",f_url)
    json_data = data
    print("请求参数:",json_data)
    resp = requests.post(f_url, json=json_data,headers=headers)
    print("响应参数:",resp.json())


if __name__ == '__main__':
    OLTP_inquiry_error()


Step 3: 写一个 provider:oltp_service.py

from flask import Flask,request
app = Flask(__name__)

@app.route('/api/v2/coperator/taxInvoice',methods=["POST"])
def create_tax_invoice():
    resp_success  ={
        "result": {
            "trackingId": "test",
            "messageTimeStamp": "2021-06-16T15:45:59.123Z",
            "chanlId": "IDC",
            "grpId": "group id"
        },
        "data": {
            "ackSignal": "0"
        }
    }
    resp_error ={
        "result": {
            "trackingId": "test",
            "messageTimeStamp": "2021-06-16T15:45:59.123Z",
            "chanlId": "IDC",
            "grpId": "group id"
        },
        "data": {
        },
        "error": {
        "code": "1234modulenm",
        "description": "사업자번호가 존재 하지 않습니다.",
        "descriptionKr": "Not Exist Business Registration Number"
        }
    }
    data = request.get_json()
    print(data)
    resp_success['result'] = data['header']
    resp_error['result'] = data['header']
    tax_no = data['data']['taxInvoiceNumber']
    if tax_no[-1:]=='0':
        return resp_error
    else:
        return resp_success

if __name__ == '__main__':
    app.run(port=8080)


Step 4: 获取预期结果
先运行oltp_service.py文件启动provider服务,然后分别运行customer_success.py和customer_error.py
最终得到正常类和异常类两种预期结果。
Step 5: 写一个正常类和一个错误类案例
根据上面两个预期结果编写两个对应的测试用例
正常类测试用例:invoice_tax_pact.py

import atexit
import requests
import unittest
from pact.consumer import Consumer
from pact.provider import Provider
from pact import Like

# 定义一个pact,消费者是ModuleB,生产者是ModuleA,契约文件存放在pacts文件夹下
pact = Consumer('customer_success').has_pact_with(Provider('oltp_service'), pact_dir='../pacts')
# 启动服务
pact.start_service()
atexit.register(pact.stop_service)

# 测试用例
class UserTesting(unittest.TestCase):

    def test_service(self):
        post_data = {
            "data": {
                "transactionType": "C",
                "brnNo": "9998199930",
                "taxInvoiceNumber": "202106161221150000000001",
                "supplierBrnNo": "9998199954",
                "creationDate": "20210616",  #
                "taxInvoiceType": "11",
                "supplyPrice": 75000000000,
                "taxAmount": 320000000,
                "buyerBrnNo": "9998199916",
                "mainItems": "전산장비",
                "remark1": "하드웨어 10종",
                "remark2": "소프트웨어 30종",
                "supplierCmpName": "서울데이터시스템",
                "buyerCmpName": "종각은행"

            },
            "header": {
                "chanlId": "IDC",
                "grpId": "GROUPID001",
                "messageTimeStamp": '2021-05-17T20:00:20.123Z',
                "trackingId": "ABC123DEF456"
            }
        }
        # 消费者定义的期望结果
        expected = {
            "result": {
                "trackingId": "test",
                "messageTimeStamp": "2021-06-16T15:45:59.123Z",
                "chanlId": "IDC",
                "grpId": "group id"
            },
            "data": {
            "ackSignal": "0"
            }
        }
        # 消费者定义的契约的实际内容。包括请求参数、请求方法、请求头、响应值等
        (pact
         .given('test service.')
         .upon_receiving('post request for oltp_service')
         .with_request(method='post', path='/api/v2/coperator/taxInvoice',body=post_data,
                       headers={'Content-Type': 'application/json'})
         # 具体校验内容
         .will_respond_with(200, body={
            'data': {
                "ackSignal": "0"
            },
            "result": {
                "trackingId": Like('hello world'),  # string类型
                "chanlId": "IDC",
                "grpId": "GROUPID001"
            },
        }))

        # pact自带一个mock服务,端口 1234,用requests向mock接口发送请求,验证mock的结果是否正确
        with pact:
            res = requests.post("http://localhost:1234/api/v2/coperator/taxInvoice",json=post_data).json()
        self.assertEqual(res['data'], expected['data'])

if __name__ == "__main__":
    ut = UserTesting()
    ut.test_service()


Step 5: 运行测试案例获取契约文件
运行上面的invoice_tax_pact.py文件后,会在对应pacts目录生成契约文件
Step 6: 运行服务和测试案例
先启动第三步创建的服务oltp_service.py
然后打开终端,进入契约文件目录,运行命令
pact-verifier --provider-base-url=http://127.0.0.1:8080 --pact-url=customer_success-oltp_service.json

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1194231.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Deepsort从入门到精通

1 ,sort和Deepsort算法 在目标检测领域,sort(Simple Online and Realtime Tracking)算法和 DeepSORT(Deep Learning for Multi-Object Tracking)算法是两种常用的目标追踪算法,它们通常与目标检…

京东数据分析:2023年Q3户外鞋服市场分析报告(冲锋衣行业销售数据分析)

从露营、骑行、徒步、桨板、垂钓、飞盘、滑雪到如今的city walk,近两年户外运动已经成为了年轻人新的生活方式。户外运动的爆发也刺激了人们对于鞋服在穿搭、场景化、专业性功能等方向的需求,户外鞋服市场迎来增长。 而全国性的降温则带给目前的户外鞋服…

嵌入式养成计划-52----ARM--开发板介绍--相关硬件基础内容介绍--GPIO讲解

一百三十一、开发板介绍 131.1 核心板介绍 131.2 拓展板 一百三十二、相关硬件基础内容介绍 132.1 PCB PCB( Printed Circuit Board),中文名称为印制电路板,又称印刷线路板, 是重要的电子部件,是电子元器…

WPS的JS宏基础(一)

基础知识 1、简单的第一个宏 //注意function只能全部用小写 function demo(){alert("你好!") }2、录制宏生成工资条 function 使用录制宏自动生成代码以JS宏为例()//使用相对引用 {Selection.Copy(undefined);ActiveCell.Offset(5, 0).Range("A1:M4").I…

【C++】new和delete深度解析

文章目录 一、new/delete是什么?1.new2.delete 二、new/delete怎么用?1.new2.delete3.new[]4.[]delete 三、new/delete为什么?1.为什么有operator new/operator delete?2.为什么要匹配使用new和delete? new/delete测试环境:visu…

使用Pytorch的一些小细节(一)

文章目录 前言数据结构-张量max函数索引函数赋值函数拼接函数 前言 由于不经常动手写代码,所以对于python语言中的常见数据结构的用法也不是很熟悉,对于pytorch中的数据结构就更加不熟悉了。之前的代码基础是基于C语言的,属性都是自己定义&a…

vue3使用element plus时遇到的问题

1.el-form中input无法输入 问题描述:在el-form中的el-input中输入数字或字母时出现卡顿,输入不进去的现象 问题原因:el-form的ref和model的名称写成了一样的单词 问题解决:两个不能一样 2.input去除边框 问题描述:…

【python海洋专题三十九】海洋指数画法--折线图样式三--不同颜色的线条

【python海洋专题三十九】海洋指数画法–折线图样式三–不同颜色的线条 数据:AMO_index 图像展示: 图片 往期推荐 图片 【python海洋专题一】查看数据nc文件的属性并输出属性到txt文件 【python海洋专题二】读取水深nc文件并水深地形图 【python海洋专题三】图像修饰之画…

文心一言 VS 讯飞星火 VS chatgpt (132)-- 算法导论11.2 4题

四、用go语言,说明在散列表内部,如何通过将所有未占用的槽位链接成一个自由链表,来分配和释放元素所占的存储空间。假定一个槽位可以存储一个标志、一个元素加上一个或两个指针。所有的字典和自由链表操作均应具有 O(1)的期望运行时间。该自由…

单元测试工具-Junit

文章目录 一. 认识Junit二. Junit中常用的注解1. Test2. Disabled3. BeforeAll & AfterAll4. BeforeEach & AfterEach 三. ParameterizedTest参数化1. 单参数2. 多参数2.1. CSV 获取参数2.2. 方法获取参数 四. Order控制测试用例的执行顺序五. 断言六. 测试套件1. 通过…

node插件MongoDB(三)—— 库mongoose 的使用和数据类型(一)

前言 提示:使用mongoose 的前提是你安装了node和 MongoDB。 mongoose 官网文档:http://mongoosejs.net/docs/index.html 文章目录 前言一、安装二、基本使用1. 打开bin目录的mongod.exe文件2. 基本使用的代码(连接mongodb 服务)3.…

【C++优先队列使用】问题总结

说明&#xff1a; 文章内容为关于priority_queue的使用总结&#xff0c;在C中要包含头文件<queue>文章内容为个人的学习整理&#xff0c;如有错误&#xff0c;欢迎指正。 文章目录 1. 优先队列默认是大根堆2. 关于优先队列和sort的比较逻辑2.1 sort的比较逻辑2.2 优先队…

【学术综述】-如何写出一篇好综述-写好综述要注意的问题

文章目录 1.前置1.1 SSD 的结构1.2 FTL的架构和作用 2 动机-why&#xff1f;3 做了什么【做了哪些方面的survey】&#xff1f;4 背景知识【上下文】5 研究的问题6 每个问题对应的解决方案 从昨天晚上【2023.11.09 22:00】到今天22:29的&#xff0c;花了一天的时间在读这篇surve…

gcc [linux]

目录 背景知识 gcc如何完成 格式 预处理&#xff08;进行宏替换&#xff09; 编译&#xff08;生成汇编&#xff09; 汇编&#xff08;生成机器可执行码&#xff09; 连接&#xff08;生成可执行文件或库文件&#xff09; 函数库 静态库 静态链接优势 动态库 动态链…

Ubuntu配置Yolov8环境并训练自己的数据集

文章目录 一、环境配置与功能测试1.1 安装1.2 目标检测1.3 实例分割1.4 分类1.5 姿态检测 二、训练数据标注三、数据集训练方法3.1 命令训练3.2 代码训练 前言&#xff1a;需要先安装CUDA和Anaconda&#xff0c;它们的安装参考我这篇文章&#xff1a;Ubuntu配置深度学习环境&am…

局域网下搭建SVN服务器

文章目录 1. 下载SVN服务器(VisualSVN Server)2. 安装SVN服务器(VisualSVN Server)3. 下载并安装TortoiseSVN4. 搭建SVN服务器 1. 下载SVN服务器(VisualSVN Server) 下载地址 2. 安装SVN服务器(VisualSVN Server) 默认安装即可 Location&#xff1a;VisualSVN Server的安装…

SpringBoot前后端分离整合cas(客户端)

SpringBoot前后端分离整合cas&#xff08;客户端&#xff09; cas认证详细流程&#xff1a; 前后端分离&#xff1a;项目前端使用nginx启动&#xff0c;后端是springBoot服务&#xff1b; nginx可以统一管理Cookie&#xff0c;避免出现跨域问题。 添加依赖 <dependency&g…

探索未来,开启无限可能:打造智慧应用,亚马逊云科技大语言模型助您一臂之力

文章目录 什么是大模型&#xff1f;大模型训练方法亚马逊云科技推出生成式AI新工具 —— aws toolkit使用教程 总结 什么是大模型&#xff1f; 近期&#xff0c;生成式大模型是人工智能领域的研究热点。这些生成式大模型&#xff0c;诸如文心一言、文心一格、ChatGPT、Stable …

strcat()用法

描述 头文件&#xff1a;<string.h>char *strcat&#xff08;char *dest&#xff0c; const char *src&#xff09;功能&#xff1a;将src字符串加到dest上&#xff0c;并返回指向dest字符串的指针。 举例 #include<stdio.h> #include<string.h> int mai…

使用非递归的方式实现归并排序

使用非递归的方式实现归并排序 话不多说&#xff0c;直接上代码&#xff1a; public class MergySort {public static void main(String[] args) {int[] nums {38, 27, 43, 3, 9, 82, 10};int[] sortedArray MergySort.mergySort(nums);// 输出排序后的数组for (int num : …