13

挑战:微服务集成测试(二)

 4 years ago
source link: http://mp.weixin.qq.com/s?__biz=MzAwMTEwNzEyOQ%3D%3D&%3Bmid=2650009580&%3Bidx=1&%3Bsn=feed2166531fe08e8e8afa07ddb7aecd
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

原文:https://codefresh.io/docker-tutorial/how-to-test-microservice-integration-with-pact/

翻译:时序

上篇文章: 挑战:微服务集成测试(一)

vIZ7BnU.jpg!web

我们的例子:

我们会测试2个小服务的集成。

服务provider是我们在jenkins plugin例子里使用过的相同的服务。它叫’bringon‘,是用Go写的一个是用mongoDB的保存软件构建信息的注册表。

我们的consumer是一个很薄的python客户端,它只知道从bringon是用构建编号来获取构建信息的。

在CDC里consumer先开始 - 我们从这来。

consumer代码现在由一个带有2个函数的client.py文件组成。我们只关注叫’build‘的函数 - 它是我们要测试的函数。

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()来保证交互是按期望进行的。

如果一切正常 - 一个叫buildreader-bringon.json的pact文件会写入到我们的工作目录。

现在我们可以将这个文件发给bringon的开发,让他们可以用这个pact来测试他们的服务。

这可以用pact-go来完成 - Golang的框架。测试看起来会是这样:

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/codefreshdemo/bringon buildreader(也就是消费者) https://github.com/antweiss/cdc-pact-demo Pact源码和例子:https://github.com/pact-foundation

在这个博客的下篇我们会展示如何让运行合约测试作为你的Codefresh(译者注:codefresh.io是一个CI/CD提供商) 流水线的一部分。

本文来自祝坤荣(时序)的微信公众号「麦芽面包,id「darkjune_think」转载请注明。交流Email: [email protected]


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK