---
title: "Testing Hono Apps"
description: "Testing Hono applications is straightforward thanks to built-in helper methods and standard Web Standards Request and Response objects. Hono provides the .request() method on application instances ..."
last_updated: "2026-10-12T08:15:16.257055+00:00"
canonical_url: "https://www.doc0.dev/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/guide/troubleshooting/testing-hono-apps"
---

## Overview

Testing Hono applications is straightforward thanks to built-in helper methods and standard Web Standards `Request` and `Response` objects. Hono provides the `.request()` method on application instances for simple endpoint testing, as well as the `testClient` helper for end-to-end typed client testing.

> [!NOTE]
> Hono runs on Web Standards, meaning standard testing frameworks like Vitest, Bun Test, or Deno Test work out of the box without complex server setup or port binding.

## Using the Built-in `.request()` Method

The `.request()` method is built directly into every Hono application instance. It lets you simulate incoming HTTP requests by passing a URL path, a full URL, or a standard `Request` object, returning a standard `Response` promise.

```ts
import { Hono } from 'hono'

const app = new Hono()

app.get('/hello', (c) => c.text('Hello Hono!'))

// Inside your test file (e.g., using Vitest or Bun Test)
test('GET /hello returns correct text', async () => {
  const res = await app.request('/hello')
  expect(res.status).toBe(200)
  expect(await res.text()).toBe('Hello Hono!')
})
```

You can pass additional request options such as headers, methods, and bodies using a standard `RequestInit` object as the second argument:

```ts
test('POST /echo returns JSON body', async () => {
  const res = await app.request('/echo', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ message: 'test' }),
  })

  expect(res.status).toBe(200)
  const data = await res.json()
  expect(data).toEqual({ message: 'test' })
})
```

## Passing Environment Bindings and Context

When testing apps that rely on environment variables, secrets, or platform bindings (such as Cloudflare Workers KV or D1 databases), you can pass bindings and execution context directly into `.request()`.

```ts
const app = new Hono<{ Bindings: { SECRET_KEY: string } }>()

app.get('/secret', (c) => {
  return c.text(c.env.SECRET_KEY)
})

test('GET /secret reads environment bindings', async () => {
  // Pass Env bindings as the third argument
  const res = await app.request('/secret', {}, { SECRET_KEY: 'my-super-secret' })
  expect(await res.text()).toBe('my-super-secret')
})
```

## Using the `testClient` Helper

### Getting Started with `testClient`

Hono provides a specialized `testClient` helper function that wraps your app in a fully typed RPC client. This allows you to invoke your endpoints programmatically with strict TypeScript type checking on both request inputs and response payloads.

1. Import `testClient` from `hono/testing`.
2. Pass your Hono app instance to `testClient(app)`.
3. Call your routes using the intuitive method-chaining syntax.

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

const app = new Hono().get('/user/:id', (c) => {
  const id = c.req.param('id')
  return c.json({ id, name: 'Alice' })
})

test('GET /user/:id via testClient', async () => {
  const client = testClient(app)

  const res = await client.user[':id'].$get({
    param: { id: '123' },
  })

  expect(res.status).toBe(200)
  const data = await res.json()
  expect(data).toEqual({ id: '123', name: 'Alice' })
})
```

> [!TIP]
> `testClient` accepts environment bindings and execution contexts as its second and third optional arguments, making it easy to test authenticated or bound routes without spinning up a real HTTP server.

## Tips and Warnings

> [!TIP]
> Keep your test suites fast by testing your Hono app instances directly with `.request()` or `testClient` instead of starting a physical network listener.

> [!WARNING]
> Remember to `await` responses when calling asynchronous methods like `.json()` or `.text()` on the returned `Response` object.

## Related

- [Errors and Exceptions](https://www.doc0.dev/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/guide/troubleshooting/errors-and-exceptions)
- [Routing and Handlers](https://www.doc0.dev/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/guide/getting-started/routing-and-handlers)


## Sitemap

See the full [sitemap](https://www.doc0.dev/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/llms.txt) for all pages in this wiki.
