如何用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

相关文章
相关标签/搜索