咱們會測試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