如何用Pact進行微服務集成測試(二)

咱們的例子:

咱們會測試2個小服務的集成。python

服務provider是咱們在jenkins plugin例子裏使用過的相同的服務。它叫’bringon‘,是用Go寫的一個是用mongoDB的保存軟件構建信息的註冊表。git

咱們的consumer是一個很薄的python客戶端,它只知道從bringon是用構建編號來獲取構建信息的。github

在CDC裏consumer先開始 - 咱們從這來。json

consumer代碼如今由一個帶有2個函數的client.py文件組成。咱們只關注叫’build‘的函數 - 它是咱們要測試的函數。segmentfault

import requests

…

def getbuild(host, port, buildnum):
    """Fetch a build by number ."""
    uri = 'http://' + host + ':' + port + '/builds/' + str(buildnum)
    return requests.get(uri).json()

爲了爲它生成pact - 咱們寫一個叫build_test.py的測試文件:後端

import atexit
import unittest
import client

from pact import Consumer, Provider

pact = Consumer('buildReader').has_pact_with(Provider('bringon'))
pact.start_service()
atexit.register(pact.stop_service)

class GetBuildInfoContract(unittest.TestCase):
  def test_get_build(self):
    true = True
    expected = {
      u'name':u'#3455',
      u'completed': true, #boolean
      u'info':{
        u'coverage':30,
        u'apiversion':0.1,
        u'swaggerlink':u'http://swagger',
        u'buildtime':230}
    }

    (pact
     .given('build 3455 exists')
     .upon_receiving('a request for build 3455')
     .with_request('get', '/builds/3455')
     .will_respond_with(200, body=expected))

    with pact:
      result = client.build(3455)

    self.assertEqual(result, expected)

這很直接 - 咱們建了一個mock的service,定義了一個指望的http reponse和body, 並調用client.build()來保證交互是定期望進行的。api

若是一切正常 - 一個叫buildreader-bringon.json的pact文件會寫入到咱們的工做目錄。微信

如今咱們能夠將這個文件發給bringon的開發,讓他們能夠用這個pact來測試他們的服務。框架

這能夠用pact-go來完成 - Golang的框架。測試看起來會是這樣:ide

func TestPact(t *testing.T) {
    go startInstrumentedBringon()
    pact := createPact()
    // Verify the Provider with local Pact Files
    log.Println("Start verify ", []string{filepath.ToSlash(fmt.Sprintf("%s/buildreader-bringon.json", pactDir))},
        fmt.Sprintf("http://localhost:%d/setup", port), fmt.Sprintf("http://localhost:%d", port), fmt.Sprintf("%s/buildReader-bringon.json", pactDir))
    err := pact.VerifyProvider(types.VerifyRequest{
        ProviderBaseURL:        fmt.Sprintf("http://localhost:%d", port),
        PactURLs:               []string{filepath.ToSlash(fmt.Sprintf("%s/buildReader-bringon.json", pactDir))},
        ProviderStatesSetupURL: fmt.Sprintf("http://localhost:%d/setup", port),
    })

    if err != nil {
        t.Fatal("Error:", err)
    }

}

記住這須要一點額外的工做。咱們須要須要實現startInstrumentedBringon()方法,它使用額外的'/setup' endpoint來定義服務狀態並啓動咱們的服務。在咱們的場景這用於建立一個入口點來知足咱們消費者的指望。咱們也須要建立一個Pact客戶端對象來校驗全部交互動做。像這樣:

func createPact() dsl.Pact {
    // Create Pact connecting to local Daemon
    log.Println("Creating pact")
    return dsl.Pact{
        Consumer: "buildreader",
        Provider: "bringon",
        LogDir:   logDir,
        PactDir:  pactDir,
    }
}

一個使用pact-go的缺點是須要你在後端運行一個常駐進程。這個進程控制服務的初始化,關閉和pact校驗。

這在容器內運行一個獨立臨時進程不太合適。

因此若是咱們須要的是用pact測試咱們的服務 - 咱們能夠使用pact-go包中的輕量級pact-provider-verifier工具。

像這樣:

pact-provider-verifier --pact-urls <path_to>/buildreader-bringon.json --provider-base-url http://localhost:8091 --provider-states-setup-url http://localhost:8091/setup

請記住在這個例子裏咱們須要實現和構建'/setup' endpoint做爲咱們服務的一部分。這在咱們想讓咱們的服務可測試時是個好主意。

服務的代碼能夠在咱們的Github找到:

bringon(也就是Provider):
https://github.com/codefreshd...
buildreader(也就是消費者)
https://github.com/antweiss/c...
Pact源碼和例子:
https://github.com/pact-found...

在這個博客的下篇咱們會展現如何讓運行合約測試做爲你的Codefresh(譯者注:codefresh.io是一個CI/CD提供商) 流水線的一部分。


本文來自祝坤榮(時序)的微信公衆號「麥芽麪包,id「darkjune_think」轉載請註明。
交流Email: zhukunrong@yeah.net

本文來自微信公衆號「麥芽麪包,id「darkjune_think」
轉載請註明。微信掃一掃關注公衆號。
交流Email: zhukunrong@yeah.net

相關文章
相關標籤/搜索