5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Hono+VitestでHTTPサーバーを起動せずにAPIテストを書く

5
Last updated at Posted at 2026-08-04

はじめに

筆者はHonoを使ってWebサービスを開発しています。APIハンドラーのテスト方法を調べる中でHonoインスタンスのrequest()メソッドを使えば、HTTPサーバーを起動せずにテストできることを知ったのでその方法を記事にまとめます。

この記事では、Honoインスタンスのrequest()メソッドを使って、VitestからAPIをテストする方法を紹介します。あわせて、HTTPサーバーを起動せずにテストできる仕組みや、テストしやすいファイル構成についても触れます。

HTTPサーバーとHonoアプリの関係

Honoは、Web標準のFetch API(RequestResponse)をベースに設計されたWebフレームワークです。HonoアプリはRequestを受け取り、Responseを返します。

今回のようにNode.js上で@hono/node-serverを使う場合、ブラウザやAPIクライアントからのHTTPリクエストは、まず@hono/node-serverが受け取ります。受け取ったリクエストはWeb標準のRequestとしてHonoアプリへ渡され、Honoアプリが返したResponseをもとにHTTPレスポンスが送信されます。

ブラウザ・APIクライアント
          │ HTTPリクエスト
          ▼
┌────────────────────┐
│   HTTPサーバー      │
│ @hono/node-server  │
└─────────┬──────────┘
          │ Requestを渡す
          ▼
┌────────────────────┐
│     Honoアプリ      │
│ Router / Middleware│
│ Handler            │
└────────────────────┘
          │ Responseを返す
          ▼
┌────────────────────┐
│   HTTPサーバー      │
│ @hono/node-server  │
└─────────┬──────────┘
          │ HTTPレスポンス
          ▼
ブラウザ・APIクライアント

テストでは、VitestからHonoアプリへ直接リクエストを渡せます。

┌──────────────┐
│   Vitest     │
└──────┬───────┘
       │ app.request()
       ▼
┌────────────────────┐
│     Honoアプリ      │
│ Router / Middleware│
│ Handler            │
└────────────────────┘

HTTPサーバーは経由しませんが、ルーティング、ミドルウェア、ハンドラーは通常どおり動作します。

サンプル実装

この記事では、HonoとVitestが導入済みであることを前提とします。

ファイル構成は次のような感じにします。

src/
├── app.ts
├── app.test.ts
└── index.ts

Honoアプリを作る

src/app.tsにアプリ本体を定義します。

import { Hono } from 'hono'

export const app = new Hono().get('/api/hello', (c) => {
  return c.json({
    message: 'Hello Hono!'
  })
})

HTTPサーバーの起動処理を分離する

src/index.tsには、HTTPサーバーの起動処理だけを記述します。

import { serve } from '@hono/node-server'
import { app } from './app.js'

serve({
  fetch: app.fetch,
  port: 3000
})

開発時はindex.tsを実行します。一方、自動テストではapp.tsだけを読み込むため、HTTPサーバーは起動しません。

app.request()を使ううえで、この分離自体が必須というわけではありませんが、アプリの定義とserve()を同じファイルに書くと、テストからアプリをimportした際にサーバーの起動処理まで実行されます。そのため、ここではファイルを分けています。

Vitestでテストする

src/app.test.tsを作成します。

import { describe, expect, test } from 'vitest'
import { app } from './app.js'

describe('APIテスト', () => {
  test('GET /api/hello', async () => {
    const response = await app.request('/api/hello')

    expect(response.status).toBe(200)
    await expect(response.json()).resolves.toEqual({
      message: 'Hello Hono!'
    })
  })
})

app.request()はWeb標準のResponseを返します。そのため、通常のfetch()と同じようにステータスコードやJSONを確認できます。

テストできる範囲

app.request()では、次の処理を確認できます。

  • ルーティング
  • ミドルウェア
  • バリデーション
  • ハンドラー
  • ステータスコードとレスポンス本文

まとめ

Honoでは、app.request()を使うことで、VitestからHTTPサーバーを起動せずにHonoアプリを直接テストできます。

const response = await app.request('/api/hello')

ぜひ参考にしてみてください!

参考資料

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?