GoravelGoravel
首页
视频
  • English
  • 简体中文
GitHub
首页
视频
  • English
  • 简体中文
GitHub
  • 前言

    • 升级指南

      • 从 v1.14 升级到 v1.15
      • 从 v1.13 升级到 v1.14
      • 历史版本升级
    • 贡献指南
    • 优秀扩展包
  • 入门指南

    • 安装
    • 配置信息
    • 文件夹结构
    • 编译
  • 核心架构

    • 请求周期
    • 服务容器
    • 服务提供者
    • Facades
  • 基本功能

    • 路由
    • HTTP 中间件
    • 控制器
    • 请求
    • 响应
    • 视图
    • Grpc
    • Session
    • 表单验证
    • 日志
  • 综合话题

    • Artisan 命令行
    • 缓存系统
    • 事件系统
    • 文件储存
    • 邮件
    • 队列
    • 任务调度
    • 本地化
    • 扩展包开发
    • 颜色
    • Strings
    • 辅助函数
  • 安全相关

    • 用户验证
    • 用户授权
    • 加密解密
    • 哈希
  • ORM

    • 快速入门
    • 模型关联
    • 数据库迁移
    • 数据填充
    • 模型工厂
  • 测试相关

    • 快速入门
    • HTTP Tests
    • Mock

HTTP Tests

  • 介绍
  • 发起 HTTP 请求
    • 自定义请求头
    • Cookies
    • WithSession
    • 调试响应
  • 构建请求体
  • 测试 JSON API
    • 断言精确匹配的 JSON
    • Fluent JSON Testing
    • 断言属性的存在/缺失
    • 断言 JSON 集合
  • 可用断言
    • 断言响应
    • AssertAccepted
    • AssertBadRequest
    • AssertConflict
    • AssertCookie
    • AssertCookieExpired
    • AssertCookieMissing
    • AssertCookieNotExpired
    • AssertCreated
    • AssertDontSee
    • AssertExactJson
    • AssertFluentJson
    • AssertForbidden
    • AssertFound
    • AssertGone
    • AssertHeader
    • AssertHeaderMissing
    • AssertInternalServerError
    • AssertJson
    • AssertJsonMissing
    • AssertMethodNotAllowed
    • AssertMovedPermanently
    • AssertNoContent
    • AssertNotAcceptable
    • AssertNotFound
    • AssertNotModified
    • AssertOk
    • AssertPartialContent
    • AssertPaymentRequired
    • AssertRequestTimeout
    • AssertSee
    • AssertSeeInOrder
    • AssertServerError
    • AssertServiceUnavailable
    • AssertStatus
    • AssertSuccessful
    • AssertTemporaryRedirect
    • AssertTooManyRequests
    • AssertUnauthorized
    • AssertUnprocessableEntity

介绍

在构建Web应用程序时,您通常需要从头到尾测试您的HTTP请求是否正常工作。Goravel的测试工具使这变得简单——您可以模拟请求并验证响应,而无需设置复杂的测试环境。

发起 HTTP 请求

测试 Goravel 中的 HTTP 接口使用了一个简单的模式。使用 TestCase 的 Http 方法,它需要一个 *testing.T 参数用于断言。该方法将返回一个实例(framework/contracts/testing.TestRequest),它处理所有常见的 HTTP 请求,如 Get 、Post 和 Put。

不需要真正的 HTTP 调用,这些方法在内部模拟了应用程序的请求周期。每个请求都返回一个响应对象(framework/contracts/testing.TestResponse),其中包含检查结果的方法。

一个简单的例子:

func (s *ExampleTestSuite) TestIndex() {
	response, err := s.Http(s.T()).Get("/users/1")
	s.Nil(err)
	response.AssertStatus(200)
}

自定义请求头

你可以使用 WithHeader 设置单个请求头,或者使用 WithHeaders 设置多个请求头:

func (s *ExampleTestSuite) TestIndex() {
    // Single header
    response, err := s.Http(s.T()).WithHeader("X-Custom-Header", "Value").Get("/users/1")
    
    // Multiple headers
    response, err := s.Http(s.T()).WithHeaders(map[string]string{
        "X-Custom-Header": "Value",
        "Accept": "application/json",
    }).Get("/users/1")
}

Cookies

你可以使用 WithCookie 或 WithCookies 方法在发起请求前设置 cookie 值。

func (s *ExampleTestSuite) TestIndex() {
	response, err := s.Http(s.T()).WithCookie("name", "krishan").Get("/users/1")

	// or use WithHeaders for multiple Headers
	response, err := s.Http(s.T()).WithHeader(map[string]string{
        "name": "krishan",
        "lang": "en",
    }).Get("/users/1")
}

WithSession

你可以使用 WithSession 方法设置 session 数据:

func (s *ExampleTestSuite) TestIndex() {
	response, err := s.Http(s.T()).WithSession(map[string]any{"role": "admin"}).Get("/users/1")
}

调试响应

在发起请求后,你可以使用 Session、Headers、Content、Cookies 或 Json 方法来检查从请求返回的数据。

func (s *ExampleTestSuite) TestIndex() {
	response, err := s.Http(s.T()).WithSession(map[string]any{"role": "admin"}).Get("/users/1")
	
	content, err := response.Content()
	
	cookies := response.Cookies()
	
	headers := response.Headers()
	
	json, err := response.Json() // response body parsed as json(map[string]any)
	
	session, err := response.Session() // returns all values stored in the current request session
}

构建请求体

如 Post、Put、Delete 等方法。Goravel 接受 io.Reader 作为第二个参数。为了简化构建请求体,框架提供了用于构建请求体的实用方法。

import "github.com/goravel/framework/support/http"

func (s *ExampleTestSuite) TestIndex() {
    builder := http.NewBody().SetField("name", "krishan")
    
    body, err := builder.Build()

    response, err := s.Http(s.T()).WithHeader("Content-Type", body.ContentType()).Post("/users", body)
}

测试 JSON API

Goravel 提供了多个帮助方法来有效地测试 JSON API 响应。它尝试将响应体解析为 Go map[string]any。如果解析失败,相关的断言也会失败。

func (s *ExampleTestSuite) TestIndex() {
    response, err := s.Http(s.T()).WithHeader("Content-Type", body.ContentType()).Post("/users", nil)
	s.Nil(err)
	
	response.AssertStatus(201).
		AssertJson(map[string]any{
			"created": true,
        })
}

使用 TestResponse 的 Json 方法可以直接访问解析后的 JSON,这样你可以检查响应体的各个元素。

json, err := response.Json()
s.Nil(err)
s.True(json["created"])

提示

AssertJson 方法检查响应是否包含所有指定的值,即使响应包含额外的字段。除非使用 AssertExactJson,否则不需要完全匹配。

断言精确匹配的 JSON

如果需要验证响应是否完全匹配您的预期 JSON(没有额外或缺少的字段),请使用 AssertExactJson 方法。

func (s *ExampleTestSuite) TestIndex() {
    response, err := s.Http(s.T()).WithHeader("Content-Type", body.ContentType()).Post("/users", nil)
	s.Nil(err)
	
	response.AssertStatus(201).
		AssertExactJson(map[string]any{
			"created": true,
        })
}

Fluent JSON Testing

Goravel 可以轻松地对 JSON 响应执行流畅的断言。使用 AssertFluentJson 方法,你可以传递一个闭包,该闭包提供了 framework/contracts/testing.AssertableJSON 的实例。这个实例允许你检查请求返回的 JSON 响应中的特定值或条件。

例如,你可以使用 Where 方法来断言 JSON 响应中是否存在特定值,使用 Missing 方法来确保属性不存在。

import contractstesting "github.com/goravel/framework/contracts/testing"

func (s *ExampleTestSuite) TestIndex() {
    response, err := s.Http(s.T()).Get("/users/1")
	s.Nil(err)
	
	response.AssertStatus(201).
		AssertFluentJson(func (json contractstesting.AssertableJSON) {
			json.Where("id", float64(1)).
				Where("name", "bowen").
				WhereNot("lang", "en").
				Missing("password")
        })
}

断言属性的存在/缺失

如果你想检查属性是否存在或缺失,可以使用 Has 和 Missing 方法:

response.AssertStatus(201).
    AssertFluentJson(func (json contractstesting.AssertableJSON) {
        json.Has("username").
            Missing("password")
    })

你也可以一次性断言多个属性的存在或缺失,使用 HasAll 和 MissingAll:

response.AssertStatus(201).
    AssertFluentJson(func (json contractstesting.AssertableJSON) {
        json.Has([]string{"username", "email"}).
            MissingAll([]string{"verified", "password"})
    })

如果你只需要检查列表中至少一个属性的存在,请使用 HasAny 方法:

response.AssertStatus(201).
    AssertFluentJson(func (json contractstesting.AssertableJSON) {
		json.HasAny([]string{"username", "email"})
    })

断言 JSON 集合

当响应包含一个对象集合时,可以使用各种方法来断言其结构和内容。

type Item struct {
    ID int `json:"id"`
}

facades.Route().Get("/", func(ctx http.Context) http.Response {
    items := []Item{
        {ID: 1},
        {ID: 2},
    }
    return ctx.Response().Json(200, map[string]{
		"items": items,
    })
}

你可以使用 Count 方法验证集合中元素的数量。要断言第一个元素的属性,请使用 First 方法,该方法提供了一个 AssertableJson 实例。同样,使用 Each 方法可以遍历所有元素并逐个断言其属性。另外,HasWithScope 方法结合了 First 和 Count 的功能,允许你断言第一个元素及其内容,同时为范围断言提供一个 AssertableJson 实例。

// Count and First
response.AssertStatus(200).
    AssertFluentJson(func(json contractstesting.AssertableJSON) {
        json.Count("items", 2).
            First("items", func(json contractstesting.AssertableJSON) {
                json.Where("id", 1)
            })
    })

// Each
response.AssertStatus(200).
    AssertFluentJson(func(json contractstesting.AssertableJSON) {
        json.Count("items", 2).
            Each("items", func(json contractstesting.AssertableJSON) {
                json.Has("id")
            })
    })

// HasWithScope
response.AssertStatus(200).
    AssertFluentJson(func(json contractstesting.AssertableJSON) {
        json.HasWithScope("items", 2, func(json contractstesting.AssertableJSON) {
            json.Where("id", 1)
        })
    })

可用断言

断言响应

AssertAcceptedAssertBadRequestAssertConflict
AssertCookieAssertCookieExpiredAssertCookieMissing
AssertCookieNotExpiredAssertCreatedAssertDontSee
AssertExactJsonAssertFluentJsonAssertForbidden
AssertFoundAssertGoneAssertHeader
AssertHeaderMissingAssertInternalServerErrorAssertJson
AssertJsonMissingAssertMethodNotAllowedAssertMovedPermanently
AssertNoContentAssertNotAcceptableAssertNotFound
AssertNotModifiedAssertOkAssertPartialContent
AssertPaymentRequiredAssertRequestTimeoutAssertSee
AssertSeeInOrderAssertServerErrorAssertServiceUnavailable
AssertStatusAssertSuccessfulAssertTemporaryRedirect
AssertTooManyRequestsAssertUnauthorizedAssertUnprocessableEntity

AssertAccepted

断言响应的 HTTP 状态码为 202 Accepted:

response.AssertAccepted()

AssertBadRequest

断言响应的 HTTP 状态码为 400 Bad Request:

response.AssertBadRequest()

AssertConflict

断言响应的 HTTP 状态码为 409 Conflict:

response.AssertConflict()

AssertCookie

断言响应包含指定名称和值的 cookie:

response.AssertCookie("name", "value")

AssertCookieExpired

断言指定的 cookie 已过期:

response.AssertCookieExpired("name")

AssertCookieMissing

断言响应不包含指定名称的 cookie:

response.AssertCookieMissing("name")

AssertCookieNotExpired

断言指定的 cookie 未过期:

response.AssertCookieNotExpired("name")

AssertCreated

断言响应的 HTTP 状态码为 201 Created:

response.AssertCreated()

AssertDontSee

断言响应不包含指定的值。第二个参数(可选)确定在检查之前是否转义值中的特殊字符。如果未提供,则默认为 true。

response.AssertDontSee([]string{"<div>"}, false)  // Do not escape special characters

AssertExactJson

断言响应的 JSON 与提供的 map[string]any 完全匹配:

response.AssertExactJson(map[string]any{"created": true})

AssertFluentJson

使用 JSON 流畅接口进行断言:

import contractstesting "github.com/goravel/framework/contracts/testing"

response.AssertFluentJson(func(json contractstesting.AssertableJSON) {
     json.Where("created", true)
})

AssertForbidden

断言响应的 HTTP 状态码为 403 Forbidden:

response.AssertForbidden()

AssertFound

断言响应的 HTTP 状态码为 302 Found:

response.AssertFound()

AssertGone

断言响应的 HTTP 状态码为 410 Gone:

response.AssertGone()

AssertHeader

断言响应包含指定名称和值的 header:

response.AssertHeader("Content-Type", "application/json")

AssertHeaderMissing

断言响应不包含指定名称的 header:

response.AssertHeaderMissing("X-Custom-Header")

AssertInternalServerError

断言响应的 HTTP 状态码为 500 Internal Server Error:

response.AssertInternalServerError()

AssertJson

断言响应的 JSON 包含提供的片段:

response.AssertJson(map[string]any{"created": true})

AssertJsonMissing

断言响应的 JSON 不包含指定的键或值:

response.AssertJsonMissing(map[string]any{"created": false})

AssertMethodNotAllowed

断言响应的 HTTP 状态码为 405 Method Not Allowed:

response.AssertMethodNotAllowed()

AssertMovedPermanently

断言响应的 HTTP 状态码为 301 Moved Permanently:

response.AssertMovedPermanently()

AssertNoContent

断言响应的 HTTP 状态码为 204 No Content:

response.AssertNoContent()

AssertNotAcceptable

断言响应的 HTTP 状态码为 406 Not Acceptable:

response.AssertNotAcceptable()

AssertNotFound

断言响应的 HTTP 状态码为 404 Not Found:

response.AssertNotFound()

AssertNotModified

断言响应的 HTTP 状态码为 304 Not Modified:

response.AssertNotModified()

AssertOk

断言响应的 HTTP 状态码为 200 OK:

response.AssertOk()

AssertPartialContent

断言响应的 HTTP 状态码为 206 Partial Content:

response.AssertPartialContent()

AssertPaymentRequired

断言响应的 HTTP 状态码为 402 Payment Required:

response.AssertPaymentRequired()

AssertRequestTimeout

断言响应的 HTTP 状态码为 408 Request Timeout:

response.AssertRequestTimeout()

AssertSee

断言响应包含指定的值。第二个参数(可选)确定在检查之前是否转义值中的特殊字符。如果未提供,则默认为 true。

response.AssertSee([]string{"<div>"}, false)  // Do not escape special characters

AssertSeeInOrder

断言响应按给定顺序包含指定的值。第二个参数(可选)确定在检查之前是否转义值中的特殊字符。如果未提供,则默认为 true。

response.AssertSeeInOrder([]string{"First", "Second"}, false)  // Do not escape special characters

AssertServerError

断言响应的 HTTP 状态码为 >= 500 , < 600:

response.AssertServerError()

AssertServiceUnavailable

断言响应的 HTTP 状态码为 503 Service Unavailable:

response.AssertServiceUnavailable()

AssertStatus

断言响应的 HTTP 状态码为指定的值:

response.AssertStatus(200)

AssertSuccessful

断言响应的 HTTP 状态码为成功的状态码(2xx):

response.AssertSuccessful()

AssertTemporaryRedirect

断言响应的 HTTP 状态码为 307 Temporary Redirect:

response.AssertTemporaryRedirect()

AssertTooManyRequests

断言响应的 HTTP 状态码为 429 Too Many Requests:

response.AssertTooManyRequests()

AssertUnauthorized

断言响应的 HTTP 状态码为 401 Unauthorized:

response.AssertUnauthorized()

AssertUnprocessableEntity

断言响应的 HTTP 状态码为 422 Unprocessable Entity:

response.AssertUnprocessableEntity()
Edit this page
Prev
快速入门
Next
Mock