golang模拟HTTP服务器和消费者驱动契约测试插件库mockingjay的使用

Golang模拟HTTP服务器和消费者驱动契约测试插件库mockingjay的使用

Mockingjay简介

Mockingjay是一个Golang库,它允许你定义消费者和生产者之间的契约,通过配置文件你可以获得:

  • 一个快速启动的模拟服务器用于集成测试
  • 可配置以模拟调用其他服务的不可预测行为
  • 消费者驱动契约测试(CDCs)来验证你的真实下游服务

运行模拟服务器

示例配置

---
- name: My very important integration point
  request:
    uri: /hello
    method: POST
    body: "Chris" # * matches any body
  response:
    code: 200
    body: '{"message": "hello, Chris"}'   # * matches any body
    headers:
      content-type: application/json

# define as many as you need...

启动服务器

$ mockingjay-server -config=example.yaml -port=1234 &
2015/04/13 14:27:54 Serving 3 endpoints defined from example.yaml on port 1234
$ curl http://localhost:1234/hello
{"message": "hello, world"}

检查配置是否与真实服务器兼容

$ mockingjay-server -config=example.yaml -realURL=http://some-real-api.com
2015/04/13 21:06:06 Test endpoint (GET /hello) is incompatible with http://some-real-api - Couldn't reach real server
2015/04/13 21:06:06 Test endpoint 2 (DELETE /world) is incompatible with http://some-real-api - Couldn't reach real server
2015/04/13 21:06:06 Failing endpoint (POST /card) is incompatible with http://some-real-api - Couldn't reach real server
2015/04/13 21:06:06 At least one endpoint was incompatible with the real URL supplied

查看Mockingjay接收的请求

http://{mockingjayhost}:{port}/requests

使模拟服务器不稳定

Mockingjay有一个"猴子"配置,可以让你的模拟服务行为不稳定。这在性能测试中很有用,可以模拟更真实的场景。

猴子配置示例

---
# Writes a different body 50% of the time
- body: "This is wrong :( "
  frequency: 0.5

# Delays initial writing of response by a second 20% of the time
- delay: 1000
  frequency: 0.2

# Returns a 404 30% of the time
- status: 404
  frequency: 0.3

# Write 10,000,000 garbage bytes 9% of the time
- garbage: 10000000
  frequency: 0.09

启动不稳定的服务器

$ mockingjay-server -config=examples/example.yaml -monkeyConfig=examples/monkey-business.yaml
2015/04/17 14:19:53 Serving 3 endpoints defined from examples/example.yaml on port 9090
2015/04/17 14:19:53 Monkey config loaded
2015/04/17 14:19:53 50% of the time | Body: This is wrong :(
2015/04/17 14:19:53 20% of the time | Delay: 1s
2015/04/17 14:19:53 30% of the time | Status: 404
2015/04/17 14:19:53  9% of the time | Garbage bytes: 10000000

构建Mockingjay

要求

  • Go 1.3+安装(设置$GOPATH等)
  • golint

构建应用

$ go get github.com/quii/mockingjay-server
$ cd $GOPATH/src/github.com/quii/mockingjay-server
$ ./build.sh

MIT许可证


更多关于golang模拟HTTP服务器和消费者驱动契约测试插件库mockingjay的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang模拟HTTP服务器和消费者驱动契约测试插件库mockingjay的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang模拟HTTP服务器与消费者驱动契约测试:mockingjay

模拟HTTP服务器

在Golang中,我们可以使用标准库net/http/httptest来轻松创建模拟HTTP服务器:

package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"
)

func main() {
	// 创建模拟服务器
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		switch r.URL.Path {
		case "/api/users":
			if r.Method == "GET" {
				w.Header().Set("Content-Type", "application/json")
				w.WriteHeader(http.StatusOK)
				fmt.Fprintln(w, `[{"id":1,"name":"John"},{"id":2,"name":"Jane"}]`)
			} else {
				w.WriteHeader(http.StatusMethodNotAllowed)
			}
		case "/api/orders":
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusOK)
			fmt.Fprintln(w, `{"orderId":"12345","status":"processing"}`)
		default:
			w.WriteHeader(http.StatusNotFound)
			fmt.Fprintln(w, `{"error":"not found"}`)
		}
	}))
	defer server.Close()

	fmt.Println("Mock server running at:", server.URL)
	
	// 这里可以添加客户端代码来测试这个模拟服务器
	// 例如使用http.Get(server.URL + "/api/users")
}

使用mockingjay进行消费者驱动契约测试

mockingjay是一个Go库,用于创建基于契约的模拟服务器。它允许你定义预期的请求和响应,并验证实际调用是否符合契约。

安装mockingjay

go get github.com/quii/mockingjay-server

基本使用示例

package main

import (
	"fmt"
	"github.com/quii/mockingjay-server/mockingjay"
	"net/http"
)

func main() {
	// 定义契约端点
	endpoints := []mockingjay.FakeEndpoint{
		{
			Name: "Get user by ID",
			CDCDisabled: false,
			Request: mockingjay.Request{
				Method: "GET",
				Path:   "/users/123",
				Headers: map[string]string{
					"Accept": "application/json",
				},
			},
			Response: mockingjay.Response{
				Code: http.StatusOK,
				Body: `{"id":123,"name":"John Doe"}`,
				Headers: map[string]string{
					"Content-Type": "application/json",
				},
			},
		},
		{
			Name: "Create user",
			CDCDisabled: false,
			Request: mockingjay.Request{
				Method: "POST",
				Path:   "/users",
				Headers: map[string]string{
					"Content-Type": "application/json",
				},
				Body: `{"name":"New User"}`,
			},
			Response: mockingjay.Response{
				Code: http.StatusCreated,
				Body: `{"id":456,"name":"New User"}`,
				Headers: map[string]string{
					"Content-Type": "application/json",
				},
			},
		},
	}

	// 创建模拟服务器
	server := mockingjay.NewServer(endpoints)
	
	fmt.Println("Mockingjay server running on", server.URL)
	
	// 保持服务器运行
	select {}
}

验证契约

mockingjay不仅可以模拟服务,还可以验证实际服务是否符合契约:

func TestRealServiceAgainstContract(t *testing.T) {
	endpoints := []mockingjay.FakeEndpoint{
		// 定义你的契约端点...
	}
	
	realServiceURL := "http://real-service:8080"
	
	// 创建验证器
	validator := mockingjay.NewValidator(endpoints, realServiceURL)
	
	// 运行验证
	results := validator.Validate()
	
	if !results.Valid() {
		t.Errorf("Real service failed contract tests: %v", results)
	}
}

高级特性

  1. 匹配器:可以使用正则表达式或自定义匹配器来匹配请求

    Request: mockingjay.Request{
        Method: "GET",
        Path:   "/users/[0-9]+",
        Headers: map[string]string{
            "Accept": "application/json",
        },
    },
    
  2. 延迟响应:模拟网络延迟

    Response: mockingjay.Response{
        Code:    http.StatusOK,
        Body:    `{"status":"ok"}`,
        Delay:   200 * time.Millisecond, // 200ms延迟
    },
    
  3. 动态响应:基于请求生成响应

    Response: mockingjay.Response{
        Code: http.StatusOK,
        BodyFunc: func(r *http.Request) string {
            return fmt.Sprintf(`{"requestedPath":"%s"}`, r.URL.Path)
        },
    },
    

实际应用建议

  1. 在CI/CD管道中:将契约测试作为持续集成的一部分
  2. 微服务开发:在服务消费者和提供者之间建立明确的契约
  3. 前端开发:在后端API完成前,使用模拟服务器进行前端开发
  4. 测试隔离:在单元测试中隔离外部依赖

通过使用这些技术,你可以创建更可靠、更可维护的API服务,并确保服务提供者和消费者之间的契约得到遵守。

回到顶部