golang RESTful API集成测试微框架插件restit的使用

golang RESTful API集成测试微框架插件restit的使用

RESTit 是一个Go微框架,用于帮助编写RESTful API的集成测试。它主要针对基于JSON的RESTful API提供测试辅助工具。

框架简介

RESTit旨在使集成测试具备以下特点:

  • 可读性强
  • 高度可重用
  • 易于修改

版本信息

RESTit库的不同版本位于不同目录下:

  • 稳定版本 (版本1):API稳定,仅接收bug修复
  • 开发版本 (版本2):正在积极开发中,可能会有新功能(可能导致API变更)

示例代码

下面是一个使用RESTit进行API测试的完整示例:

package main

import (
	"testing"
	"github.com/go-restit/restit/v1"
)

// 定义测试数据结构
type Post struct {
	ID    int    `json:"id"`
	Title string `json:"title"`
	Body  string `json:"body"`
}

func TestGetPost(t *testing.T) {
	// 创建测试客户端
	client := restit.New("https://jsonplaceholder.typicode.com")
	
	// 定义期望的响应结构
	var post Post
	
	// 执行GET请求并验证响应
	client.Get("/posts/1").
		Expect(t).
		Status(200). // 期望状态码200
		Header("Content-Type", "application/json"). // 期望响应头
		JSON(&post). // 解析JSON响应
		Run()
	
	// 验证响应数据
	if post.ID != 1 {
		t.Errorf("expected post ID to be 1, got %d", post.ID)
	}
}

func TestCreatePost(t *testing.T) {
	// 创建测试客户端
	client := restit.New("https://jsonplaceholder.typicode.com")
	
	// 准备请求数据
	newPost := Post{
		Title: "Test Post",
		Body:  "This is a test post",
	}
	
	// 定义期望的响应结构
	var createdPost Post
	
	// 执行POST请求并验证响应
	client.Post("/posts").
		JSON(newPost). // 设置请求体
		Expect(t).
		Status(201). // 期望状态码201
		JSON(&createdPost). // 解析JSON响应
		Run()
	
	// 验证响应数据
	if createdPost.Title != newPost.Title {
		t.Errorf("expected title to be %q, got %q", newPost.Title, createdPost.Title)
	}
}

主要功能

  1. 请求构建:支持GET、POST、PUT、DELETE等HTTP方法
  2. 响应验证:可以验证状态码、响应头和响应体
  3. JSON处理:自动序列化和反序列化JSON数据
  4. 测试断言:内置丰富的断言方法

错误报告

如果发现问题,可以通过项目的issue tracker提交错误报告。同时欢迎提交补丁和pull请求。

这个示例展示了如何使用RESTit进行基本的API测试,包括GET和POST请求的发送与验证。你可以根据实际需求扩展这个基础示例。


更多关于golang RESTful API集成测试微框架插件restit的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang RESTful API集成测试微框架插件restit的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


使用restit进行Golang RESTful API集成测试

restit是一个轻量级的Golang RESTful API集成测试框架,它提供了简洁的API来测试HTTP服务。下面我将介绍如何使用restit进行API测试。

安装restit

首先安装restit包:

go get github.com/yookoala/restit

基本用法

1. 简单GET请求测试

package main

import (
	"fmt"
	"github.com/yookoala/restit"
	"net/http"
	"net/http/httptest"
	"testing"
)

func TestGetRequest(t *testing.T) {
	// 创建一个测试服务器
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, `{"status": "ok", "message": "success"}`)
	}))
	defer ts.Close()

	// 使用restit发送GET请求
	resp, err := restit.Get(restit.URL(ts.URL))
	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}

	// 验证响应状态码
	if resp.StatusCode() != http.StatusOK {
		t.Errorf("Expected status 200, got %d", resp.StatusCode())
	}

	// 验证JSON响应内容
	expected := `{"status": "ok", "message": "success"}`
	if resp.String() != expected+"\n" {
		t.Errorf("Expected response %q, got %q", expected, resp.String())
	}
}

2. POST请求测试

func TestPostRequest(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// 验证请求体
		body := make([]byte, r.ContentLength)
		r.Body.Read(body)
		if string(body) != `{"name":"test"}` {
			w.WriteHeader(http.StatusBadRequest)
			return
		}
		w.WriteHeader(http.StatusCreated)
		fmt.Fprintln(w, `{"id": 123}`)
	}))
	defer ts.Close()

	// 发送POST请求
	resp, err := restit.Post(
		restit.URL(ts.URL),
		restit.ContentType("application/json"),
		restit.Body(`{"name":"test"}`),
	)
	if err != nil {
		t.Errorf("Unexpected error: %v", err)
	}

	// 验证响应状态码
	if resp.StatusCode() != http.StatusCreated {
		t.Errorf("Expected status 201, got %d", resp.StatusCode())
	}

	// 解析JSON响应
	var result struct {
		ID int `json:"id"`
	}
	if err := resp.JSON(&result); err != nil {
		t.Errorf("Failed to parse JSON: %v", err)
	}
	if result.ID != 123 {
		t.Errorf("Expected ID 123, got %d", result.ID)
	}
}

3. 更复杂的测试场景

func TestAuthAPI(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// 验证授权头
		if r.Header.Get("Authorization") != "Bearer test-token" {
			w.WriteHeader(http.StatusUnauthorized)
			return
		}
		
		// 根据路径返回不同响应
		switch r.URL.Path {
		case "/user":
			fmt.Fprintln(w, `{"name": "John", "age": 30}`)
		case "/items":
			fmt.Fprintln(w, `[{"id":1,"name":"item1"},{"id":2,"name":"item2"}]`)
		default:
			w.WriteHeader(http.StatusNotFound)
		}
	}))
	defer ts.Close()

	// 测试带认证头的请求
	t.Run("TestAuthenticatedRequest", func(t *testing.T) {
		resp, err := restit.Get(
			restit.URL(ts.URL+"/user"),
			restit.AddHeader("Authorization", "Bearer test-token"),
		)
		if err != nil {
			t.Fatal(err)
		}
		
		if resp.StatusCode() != http.StatusOK {
			t.Errorf("Expected status 200, got %d", resp.StatusCode())
		}
		
		var user struct {
			Name string `json:"name"`
			Age  int    `json:"age"`
		}
		if err := resp.JSON(&user); err != nil {
			t.Fatal(err)
		}
		if user.Name != "John" || user.Age != 30 {
			t.Errorf("Unexpected user data: %+v", user)
		}
	})

	// 测试未授权请求
	t.Run("TestUnauthorizedRequest", func(t *testing.T) {
		resp, err := restit.Get(restit.URL(ts.URL+"/user"))
		if err != nil {
			t.Fatal(err)
		}
		if resp.StatusCode() != http.StatusUnauthorized {
			t.Errorf("Expected status 401, got %d", resp.StatusCode())
		}
	})
}

高级特性

1. 使用Expect简化断言

func TestExpect(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, `{"status": "ok"}`)
	}))
	defer ts.Close()

	resp, err := restit.Get(restit.URL(ts.URL))
	if err != nil {
		t.Fatal(err)
	}

	// 使用Expect进行断言
	resp.
		Expect(t).                                  // 开始断言链
		Status(http.StatusOK).                      // 验证状态码
		Header("Content-Type", "application/json"). // 验证头部
		JSON(map[string]interface{}{               // 验证JSON
			"status": "ok",
		})
}

2. 测试文件上传

func TestFileUpload(t *testing.T) {
	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		file, header, err := r.FormFile("file")
		if err != nil {
			w.WriteHeader(http.StatusBadRequest)
			return
		}
		defer file.Close()
		
		if header.Filename != "test.txt" {
			w.WriteHeader(http.StatusBadRequest)
			return
		}
		
		w.WriteHeader(http.StatusOK)
		fmt.Fprintln(w, `{"size": `+fmt.Sprint(header.Size)+`}`)
	}))
	defer ts.Close()

	// 创建一个临时文件
	tmpFile, err := os.CreateTemp("", "test-*.txt")
	if err != nil {
		t.Fatal(err)
	}
	defer os.Remove(tmpFile.Name())
	
	if _, err := tmpFile.WriteString("test content"); err != nil {
		t.Fatal(err)
	}
	tmpFile.Close()

	// 发送文件上传请求
	resp, err := restit.Post(
		restit.URL(ts.URL),
		restit.File("file", tmpFile.Name()),
	)
	if err != nil {
		t.Fatal(err)
	}

	resp.Expect(t).
		Status(http.StatusOK).
		JSON(map[string]interface{}{
			"size": 12, // "test content"的长度
		})
}

总结

restit提供了简洁的API来测试RESTful服务,主要特点包括:

  1. 支持各种HTTP方法(GET, POST, PUT, DELETE等)
  2. 方便设置请求头、内容类型和请求体
  3. 支持文件上传测试
  4. 提供Expect链式断言简化测试代码
  5. 支持JSON响应解析和验证

对于更复杂的测试场景,可以结合标准库的httptest和restit一起使用。restit特别适合在开发微服务时进行集成测试,保持测试代码简洁易读。

回到顶部