契約測試:python 版本case

原文:微服務(wù)下的契約測試—Python版 - 知乎 (zhihu.com)
契約測試--pact框架使用 - 簡書 (jianshu.com)

我們用實例更好的理解一下契約測試

  • 1、有一個獲取用戶信息的接口 /user,參數(shù)name,調(diào)用地址:http://0.0.0.0:5000/user?name=zhoujielun,返回對應(yīng)的個人信息普通的接口測試,從客戶端出發(fā),通過設(shè)計不同的參數(shù)組合盡可能的覆蓋更多的邏輯分支,比如name=zhoujielun,name=123等等,為了說明契約測試,我們盡量簡單說明使用unittest單測框架來做接口測試,我們關(guān)注接口的返回代碼如 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,結(jié)果如下:

======================================================================
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的測試用例是失敗的,預(yù)期結(jié)果和實際調(diào)用結(jié)果不相符

上面是一個簡單的接口測試用例,對于普通服務(wù)的接口測試來說,這種測試方法是可行的,沒有問題但是在微服務(wù)架構(gòu)下,會遇到一個問題:某服務(wù)X改了接口返回的數(shù)據(jù)或者結(jié)構(gòu),比如原先的返回code字段變更成了status或者某個home字段的值,按照上面的測試方法,我們獨立對X測試的時候,優(yōu)先考慮的是X服務(wù)的可用性和正確性,很難去實際度量X的上游調(diào)用方他的代碼在實際調(diào)用X接口的時候是否正常,服務(wù)他的預(yù)期,基于此,微服務(wù)的一個組件,他的上游組件數(shù)量是N多。

生產(chǎn)者按照自己的意愿去生產(chǎn)接口,導致這些接口無法滿足消費者的需求,從而引發(fā)各種開發(fā)、測試問題,顯然不是我們想要的結(jié)果。契約測試的出現(xiàn)就是為了解決這種需求與實際不對等的問題,本質(zhì)上其實是一個基于mock服務(wù)的接口測試

通俗的契約測試核心思想:對于任意兩個存在調(diào)用關(guān)系的服務(wù)組件A和B,A需要調(diào)用B的接口api_01,從契約的角度出發(fā),我們需要從A這個消費者的角度制造一個契約(或者叫合同吧),合同里面約定了接口、接口入?yún)⒁约霸谌雲(yún)⒌那疤峤涌趹?yīng)該給出什么樣的返回。然后B組件的接口api_01在開發(fā)的時候需要按照契約的要求去開發(fā),開發(fā)完成之后由B端人員發(fā)起契約測試或者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,生產(chǎn)者是ModuleB,契約文件存放在pacts文件夾下
pact = Consumer('ModuleA').has_pact_with(Provider('ModuleB'), pact_dir='./pacts’)
# 啟動服務(wù)
pact.start_service()
atexit.register(pact.stop_service)

class UserTesting(unittest.TestCase):
    def runTest(self):
        self.test_lizeyang()
    def test_lizeyang(self):
        # 預(yù)期結(jié)果
        expected = {"age": 222, "home": "china"}
        # 契約的實際內(nèi)容
        (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))
        # 調(diào)用pact自帶的mock服務(wù),注冊接口
        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文件夾下會自動生產(chǎn)一個契約文件modulea-moduleb.json,內(nèi)容如下。

{
  "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"
    }
  }
}

這個契約文件定義了調(diào)用生產(chǎn)者ModuleB時候的測試用例和返回報文的格式 B端拿到這份契約之后,需要按照個契約的內(nèi)容完成接口開發(fā)以及自測 自測方法:

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

可以看到自測接口與實際的返回是不一致的,開發(fā)需要按照契約修改自己的代碼來通過契約測試即可。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 16宿命:用概率思維提高你的勝算 以前的我是風險厭惡者,不喜歡去冒險,但是人生放棄了冒險,也就放棄了無數(shù)的可能。 ...
    yichen大刀閱讀 7,828評論 0 4
  • 公元:2019年11月28日19時42分農(nóng)歷:二零一九年 十一月 初三日 戌時干支:己亥乙亥己巳甲戌當月節(jié)氣:立冬...
    石放閱讀 7,449評論 0 2
  • 今天上午陪老媽看病,下午健身房跑步,晚上想想今天還沒有斷舍離,馬上做,衣架和旁邊的的布衣架,一看亂亂,又想想自己是...
    影子3623253閱讀 3,062評論 3 8
  • 年紀越大,人的反應(yīng)就越遲鈍,腦子就越不好使,計劃稍有變化,就容易手忙腳亂,亂了方寸。 “玩壞了”也是如此,不但會亂...
    玩壞了閱讀 2,343評論 2 1
  • 感動 我在你的眼里的樣子,就是你的樣子。 相互內(nèi)化 沒有絕對的善惡 有因必有果 當你以自己的價值觀幸福感去要求其他...
    周粥粥叭閱讀 1,740評論 1 5

友情鏈接更多精彩內(nèi)容