Skip to content

测试助手

🌐 Testing Helper

Testing Helper 提供使 Hono 应用测试更容易的功能。

🌐 The Testing Helper provides functions to make testing of Hono applications easier.

导入

🌐 Import

ts
import { Hono } from 'hono'
import { testClient } from 'hono/testing'

testClient()

testClient() 函数以 Hono 的一个实例作为第一个参数,并返回一个根据你的 Hono 应用路由类型化的对象,类似于 Hono Client。这使你能够在测试中以类型安全的方式调用已定义的路由,并在编辑器中享受自动补全功能。

🌐 The testClient() function takes an instance of Hono as its first argument and returns an object typed according to your Hono application's routes, similar to the Hono Client. This allows you to call your defined routes in a type-safe manner with editor autocompletion within your tests.

关于类型推断的重要说明:

为了使 testClient 正确推断你的路由类型并提供自动补全,你必须直接在 Hono 实例上使用链式方法定义路由

🌐 For the testClient to correctly infer the types of your routes and provide autocompletion, you must define your routes using chained methods directly on the Hono instance.

类型推断依赖于类型通过链式调用的 .get().post() 等流动。如果你在创建 Hono 实例之后单独定义路由(例如“Hello World”示例中显示的常见模式:const app = new Hono(); app.get(...)),testClient 将不会拥有特定路由所需的类型信息,而且你将无法获得类型安全的客户端功能。

🌐 The type inference relies on the type flowing through the chained .get(), .post(), etc., calls. If you define routes separately after creating the Hono instance (like the common pattern shown in the "Hello World" example: const app = new Hono(); app.get(...)), the testClient will not have the necessary type information for specific routes, and you won't get the type-safe client features.

示例:

这个例子能运行是因为 .get() 方法直接链式调用在 new Hono() 调用上:

🌐 This example works because the .get() method is chained directly onto the new Hono() call:

ts
// index.ts
const app = new Hono().get('/search', (c) => {
  const query = c.req.query('q')
  return c.json({ query: query, results: ['result1', 'result2'] })
})

export default app
ts
// index.test.ts
import { Hono } from 'hono'
import { testClient } from 'hono/testing'
import { describe, it, expect } from 'vitest' // Or your preferred test runner
import app from './app'

describe('Search Endpoint', () => {
  // Create the test client from the app instance
  const client = testClient(app)

  it('should return search results', async () => {
    // Call the endpoint using the typed client
    // Notice the type safety for query parameters (if defined in the route)
    // and the direct access via .$get()
    const res = await client.search.$get({
      query: { q: 'hono' },
    })

    // Assertions
    expect(res.status).toBe(200)
    expect(await res.json()).toEqual({
      query: 'hono',
      results: ['result1', 'result2'],
    })
  })
})

要在你的测试中包含头信息,请在调用中将它们作为第二个参数传递。第二个参数还可以将 init 属性作为 RequestInit 对象,该对象允许你设置头信息、方法、正文等。有关 init 属性的更多信息,请点击这里了解。

🌐 To include headers in your test, pass them as the second parameter in the call. The second parameter can also take an init property as a RequestInit object, allowing you to set headers, method, body, etc. Learn more about the init property here.

ts
// index.test.ts
import { Hono } from 'hono'
import { testClient } from 'hono/testing'
import { describe, it, expect } from 'vitest' // Or your preferred test runner
import app from './app'

describe('Search Endpoint', () => {
  // Create the test client from the app instance
  const client = testClient(app)

  it('should return search results', async () => {
    // Include the token in the headers and set the content type
    const token = 'this-is-a-very-clean-token'
    const res = await client.search.$get(
      {
        query: { q: 'hono' },
      },
      {
        headers: {
          Authorization: `Bearer ${token}`,
          'Content-Type': `application/json`,
        },
      }
    )

    // Assertions
    expect(res.status).toBe(200)
    expect(await res.json()).toEqual({
      query: 'hono',
      results: ['result1', 'result2'],
    })
  })
})

Hono 中文网 - 粤ICP备13048890号