Golang中如何使用Rest-assured和Cucumber进行测试

Golang中如何使用Rest-assured和Cucumber进行测试 你好,我正在测试一个 API,并希望采用 BDD(行为驱动开发)风格进行。

我之前使用过 Java、RestAssured 和 Cucumber,但现在我需要在 Go 语言中完成这项工作,最好是用 Go。有人有经验可以为我指明正确的方向吗?

我搜索了一下,发现一个叫 Baloo 的工具,看起来还不错,还有一个叫 Go-Rest-Assured 的。但这些库好用吗?

还有一个叫 GoDog 的工具,它类似于 Cucumber。但我对 Go 语言和这些库都没有经验。

2 回复

我还没有使用过任何BDD测试库,但我听说大多数项目都使用ginkgo和testify。

GitHub

onsi/ginkgo

头像

Go语言的BDD测试框架。通过创建GitHub账户为onsi/ginkgo的开发做出贡献。

更多关于Golang中如何使用Rest-assured和Cucumber进行测试的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go语言中实现BDD风格的API测试,可以使用以下组合:

1. 测试框架选择

GoDog + GoRestAssured

这是最接近Java中RestAssured+Cucumber的方案:

// go.mod 依赖
require (
    github.com/cucumber/godog v0.13.0
    github.com/steinfletcher/apitest v1.5.15
    // 或使用:github.com/go-resty/resty/v2 v2.7.0
)

// features/api_test.go
package test

import (
    "context"
    "encoding/json"
    "fmt"
    "testing"
    
    "github.com/cucumber/godog"
    "github.com/go-resty/resty/v2"
)

type apiFeature struct {
    client     *resty.Client
    response   *resty.Response
    requestBody map[string]interface{}
}

func (a *apiFeature) iSendRequestTo(method, endpoint string) error {
    var err error
    switch method {
    case "GET":
        a.response, err = a.client.R().Get(endpoint)
    case "POST":
        a.response, err = a.client.R().
            SetHeader("Content-Type", "application/json").
            SetBody(a.requestBody).
            Post(endpoint)
    case "PUT":
        a.response, err = a.client.R().
            SetHeader("Content-Type", "application/json").
            SetBody(a.requestBody).
            Put(endpoint)
    }
    return err
}

func (a *apiFeature) theResponseCodeShouldBe(code int) error {
    if a.response.StatusCode() != code {
        return fmt.Errorf("expected status %d, got %d", 
            code, a.response.StatusCode())
    }
    return nil
}

func (a *apiFeature) theResponseShouldContainJSON(key, value string) error {
    var result map[string]interface{}
    if err := json.Unmarshal(a.response.Body(), &result); err != nil {
        return err
    }
    
    if val, ok := result[key]; !ok || fmt.Sprintf("%v", val) != value {
        return fmt.Errorf("key %s not found or value mismatch", key)
    }
    return nil
}

func (a *apiFeature) iSetRequestBody(data *godog.DocString) error {
    return json.Unmarshal([]byte(data.Content), &a.requestBody)
}

func InitializeScenario(ctx *godog.ScenarioContext) {
    api := &apiFeature{
        client: resty.New(),
        requestBody: make(map[string]interface{}),
    }
    
    ctx.BeforeScenario(func(*godog.Scenario) {
        api.client = resty.New().
            SetBaseURL("http://localhost:8080").
            SetTimeout(10)
        api.requestBody = make(map[string]interface{})
    })
    
    ctx.Step(`^I send (GET|POST|PUT) request to "([^"]*)"$`, 
        api.iSendRequestTo)
    ctx.Step(`^the response code should be (\d+)$`, 
        api.theResponseCodeShouldBe)
    ctx.Step(`^the response should contain JSON "([^"]*)" with value "([^"]*)"$`, 
        api.theResponseShouldContainJSON)
    ctx.Step(`^I set request body:$`, api.iSetRequestBody)
}

func TestFeatures(t *testing.T) {
    suite := godog.TestSuite{
        ScenarioInitializer: InitializeScenario,
        Options: &godog.Options{
            Format:   "pretty",
            Paths:    []string{"features"},
            TestingT: t,
        },
    }
    
    if suite.Run() != 0 {
        t.Fatal("non-zero status returned, failed to run feature tests")
    }
}

2. 特征文件示例

# features/user_api.feature
Feature: User API Testing

  Scenario: Get user by ID
    Given I send GET request to "/api/users/1"
    Then the response code should be 200
    And the response should contain JSON "id" with value "1"
    And the response should contain JSON "name" with value "John Doe"

  Scenario: Create new user
    Given I set request body:
      """
      {
        "name": "Jane Smith",
        "email": "jane@example.com"
      }
      """
    When I send POST request to "/api/users"
    Then the response code should be 201
    And the response should contain JSON "status" with value "created"

3. 替代方案:Ginkgo + Gomega

如果你更喜欢xUnit风格的BDD:

// go.mod
require (
    github.com/onsi/ginkgo/v2 v2.11.0
    github.com/onsi/gomega v1.27.10
)

// api_test.go
package api_test

import (
    . "github.com/onsi/ginkgo/v2"
    . "github.com/onsi/gomega"
    "github.com/go-resty/resty/v2"
    "encoding/json"
)

var _ = Describe("User API", func() {
    var client *resty.Client
    var response *resty.Response
    
    BeforeEach(func() {
        client = resty.New().
            SetBaseURL("http://localhost:8080")
    })
    
    Describe("GET /api/users/{id}", func() {
        Context("when user exists", func() {
            BeforeEach(func() {
                var err error
                response, err = client.R().Get("/api/users/1")
                Expect(err).NotTo(HaveOccurred())
            })
            
            It("should return status 200", func() {
                Expect(response.StatusCode()).To(Equal(200))
            })
            
            It("should return user data", func() {
                var result map[string]interface{}
                err := json.Unmarshal(response.Body(), &result)
                Expect(err).NotTo(HaveOccurred())
                Expect(result["id"]).To(Equal(float64(1)))
            })
        })
    })
})

4. 运行测试

# 安装依赖
go mod init your-project
go get github.com/cucumber/godog
go get github.com/go-resty/resty/v2

# 运行GoDog测试
go test -v ./...

# 或使用标签运行特定测试
go test -v -tags=godog ./...

5. 关于你提到的工具

  • GoDog: 是Go语言中最成熟的Cucumber实现,完全支持Gherkin语法
  • Go-Resty: 比Baloo更活跃的HTTP客户端,类似RestAssured
  • Baloo: 虽然可用,但维护不如Go-Resty活跃
  • apitest: 另一个不错的API测试库,更轻量级

推荐使用GoDog + Go-Resty组合,这是目前Go生态中最接近Java RestAssured+Cucumber体验的方案。

回到顶部