契约测试:python 版本case

原文:微服务下的契约测试—Python版 - 知乎 (zhihu.com)
契约测试--pact框架使用 - 简书 (jianshu.com)

我们用实例更好的理解一下契约测试

  • 1、有一个获取用户信息的接口 /user,参数name,调用地址:http://0.0.0.0:5000/user?name=zhoujielun,返回对应的个人信息普通的接口测试,从客户端出发,通过设计不同的参数组合尽可能的覆盖更多的逻辑分支,比如name=zhoujielun,name=123等等,为了说明契约测试,我们尽量简单说明使用unittest单测框架来做接口测试,我们关注接口的返回代码如 user_unittest.py所示
def test_lizeyang(self):
    """name=lizeyang的测试用例"""
    expect = { "age": 21, "home": "china"}
    res = requests.get("http://127.0.0.1:5000/user?name=lizeyang").json()
    self.assertEqual(res, expect)
def test_zhoujielun(self):
    """name=zhoujielun的测试用例"""
    expect = { "age": 21, "home": "america"}
    res = requests.get("http://127.0.0.1:5000/user?name=zhoujielun").json()
    self.assertEqual(res, expect)
    self.assertEqual(res, expect)

运行python user_unittest.py,结果如下:

======================================================================
FAIL: test_lizeyang (__main__.UserTesting)
name=lizeyang的测试用例
----------------------------------------------------------------------
Traceback (most recent call last):
  File "user_unittest.py", line 19, in test_lizeyang
    self.assertEqual(res, expect)
AssertionError: {u'errmsg': u'user not exist.'} != {'home': 'china', 'age': 21}
- {u'errmsg': u'user not exist.'}
+ {'age': 21, 'home': 'china'}
----------------------------------------------------------------------
Ran 2 tests in 0.015s
FAILED (failures=1)

可以看到,name=lizeyang的测试用例是失败的,预期结果和实际调用结果不相符

上面是一个简单的接口测试用例,对于普通服务的接口测试来说,这种测试方法是可行的,没有问题但是在微服务架构下,会遇到一个问题:某服务X改了接口返回的数据或者结构,比如原先的返回code字段变更成了status或者某个home字段的值,按照上面的测试方法,我们独立对X测试的时候,优先考虑的是X服务的可用性和正确性,很难去实际度量X的上游调用方他的代码在实际调用X接口的时候是否正常,服务他的预期,基于此,微服务的一个组件,他的上游组件数量是N多。

生产者按照自己的意愿去生产接口,导致这些接口无法满足消费者的需求,从而引发各种开发、测试问题,显然不是我们想要的结果。契约测试的出现就是为了解决这种需求与实际不对等的问题,本质上其实是一个基于mock服务的接口测试

通俗的契约测试核心思想:对于任意两个存在调用关系的服务组件A和B,A需要调用B的接口api_01,从契约的角度出发,我们需要从A这个消费者的角度制造一个契约(或者叫合同吧),合同里面约定了接口、接口入参以及在入参的前提接口应该给出什么样的返回。然后B组件的接口api_01在开发的时候需要按照契约的要求去开发,开发完成之后由B端人员发起契约测试或者CI集成测试

契约测试 = 测试左移 + mock + 接口测试

#!/usr/bin/python
# -*- encoding:utf-8 -*-
import atexit
import requests
import unittest
from pact import EachLike, SomethingLike, Term
from pact.consumer import Consumer
from pact.provider import Provider
# 定义一个pact,消费者是ModuleA,生产者是ModuleB,契约文件存放在pacts文件夹下
pact = Consumer('ModuleA').has_pact_with(Provider('ModuleB'), pact_dir='./pacts’)
# 启动服务
pact.start_service()
atexit.register(pact.stop_service)

class UserTesting(unittest.TestCase):
    def runTest(self):
        self.test_lizeyang()
    def test_lizeyang(self):
        # 预期结果
        expected = {"age": 222, "home": "china"}
        # 契约的实际内容
        (pact
         .given('test lizeyang this user.')
         .upon_receiving('a request for the user `lizeyang`')
         .with_request('get', '/user', query={"name": "lizeyang"})
         .will_respond_with(200, body=expected))
        # 调用pact自带的mock服务,注册接口
        with pact:
            res = requests.get("http://localhost:1234/user?name=lizeyang").json()
        self.assertEqual(res, expected)

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

运行python user_pact_test.py之后,

INFO  WEBrick 1.3.1
INFO  ruby 2.2.2 (2015-04-13) [x86_64-darwin13]
INFO  WEBrick::HTTPServer#start: pid=63533 port=1234
{u'home': u'china', u'age': 222}
INFO  going to shutdown ...
INFO  WEBrick::HTTPServer#start done.

这时,在contracts/pacts文件夹下会自动生产一个契约文件modulea-moduleb.json,内容如下。

{
  "consumer": {
    "name": "ModuleA"
  },
  "provider": {
    "name": "ModuleB"
  },
  "interactions": [
    {
      "description": "a request for the user `lizeyang`”,  # 描述
      "providerState": "test lizeyang this user.”,
      "request": {
        "method": "get",
        "path": "/user",
        "query": "name=lizeyang"
      },
      "response": {
        "status": 200,
        "headers": {
        },
        "body": {
          "home": "china",
          "age": 222
        }
      }
    }
  ],
  "metadata": {
    "pactSpecification": {
      "version": "2.0.0"
    }
  }
}

这个契约文件定义了调用生产者ModuleB时候的测试用例和返回报文的格式 B端拿到这份契约之后,需要按照个契约的内容完成接口开发以及自测 自测方法:

pact-verifier --provider-base-url=http://127.0.0.1:5000 --pact-url=./contracts/pacts/test_sender-service_001.json
image

可以看到自测接口与实际的返回是不一致的,开发需要按照契约修改自己的代码来通过契约测试即可。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 16宿命:用概率思维提高你的胜算 以前的我是风险厌恶者,不喜欢去冒险,但是人生放弃了冒险,也就放弃了无数的可能。 ...
    yichen大刀阅读 9,109评论 0 4
  • 公元:2019年11月28日19时42分农历:二零一九年 十一月 初三日 戌时干支:己亥乙亥己巳甲戌当月节气:立冬...
    石放阅读 7,725评论 0 2
  • 今天上午陪老妈看病,下午健身房跑步,晚上想想今天还没有断舍离,马上做,衣架和旁边的的布衣架,一看乱乱,又想想自己是...
    影子3623253阅读 3,095评论 3 8
  • 年纪越大,人的反应就越迟钝,脑子就越不好使,计划稍有变化,就容易手忙脚乱,乱了方寸。 “玩坏了”也是如此,不但会乱...
    玩坏了阅读 2,389评论 2 1
  • 感动 我在你的眼里的样子,就是你的样子。 相互内化 没有绝对的善恶 有因必有果 当你以自己的价值观幸福感去要求其他...
    周粥粥叭阅读 1,763评论 1 5

友情链接更多精彩内容