デプロイのためテスト環境導入したがsupertest で app.address is not a function が出た
supertestでExpressアプリをテストする際、TypeError: app.address is not a function
エラーが発生。原因はserverインスタンスではなくappインスタンスをエクスポートすべきところを間違えていたこと。適切なオブジェクトのエクスポートと環境条件分岐で解決。
背景と課題
Node.js バックエンドアプリケーションでJestとsupertestを使った認証機能のテストを実装している際、設定段階で躓きました。supertestは、Express アプリケーションに対してHTTPリクエストを送信してレスポンスをテストするライブラリです。一方、JestはJavaScript用のテスティングフレームワークで、テストの構造化と実行を担当します。
開発環境では通常通りサーバーが起動していたものの、テスト実行時にTypeError: app.address is not a function
エラーが発生。このエラーはsupertestがExpressアプリケーションインスタンスを期待しているにも関わらず、異なるオブジェクト(この場合はサーバーインスタンス)を受け取った際に発生します。
事象の再現手順
問題が発生していたコード構成は以下の通りです:
// server.js(修正前)
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;
// ミドルウェアとルート設定
app.use(express.json());
app.get('/api/test', (req, res) => {
res.json({ message: 'Test endpoint' });
});
const server = app.listen(port, () => {
console.log(`Server is running on http://localhost:${port}`);
});
module.exports = server; // ❌ 問題箇所
// test/app.test.js
const request = require('supertest');
const app = require('../server');
describe('Authentication Tests', () => {
test('GET /api/test should return test message', async () => {
const response = await request(app)
.get('/api/test')
.expect(200);
expect(response.body.message).toBe('Test endpoint');
});
});
テスト実行時に以下のエラーが発生:
TypeError: app.address is not a function
at Test.serverAddress (node_modules/supertest/lib/test.js:XX:XX)
解決までの思考プロセス
最初の仮説は「supertest環境ではappオブジェクトが必要だが、server.jsでアプリとサーバーを同じファイルでコーディングしているからエラーが発生している」でした。
この仮説を検証するため、まずsupertestのドキュメントを確認しました。supertestはrequest(app)
の形でExpressアプリケーションインスタンスを期待していることが判明。しかし、コードではmodule.exports = server
としてサーバーインスタンスをエクスポートしていました。
問題の核心は以下の点でした:
- supertestはExpressアプリケーション(
app
)を必要とする - エクスポートしていたのはサーバーインスタンス(
server
) - テスト環境でもサーバーが起動してしまい、ポート競合の可能性
最終的な解決策
責任の分離とオブジェクトの適切なエクスポートで問題を解決しました:
// app.js(新規作成)
const express = require('express');
const app = express();
// ミドルウェア設定
app.use(express.json());
// ルート定義
app.get('/api/test', (req, res) => {
res.json({ message: 'Test endpoint' });
});
module.exports = app; // ✅ appインスタンスをエクスポート
// server.js(修正後)
require('dotenv').config();
const app = require('./app');
const port = process.env.PORT || 3000;
// テスト環境以外でのみサーバー起動
if (process.env.NODE_ENV !== 'test') {
app.listen(port, () => {
console.log(`Server is running on http://localhost:${port}`);
});
}
module.exports = app; // ✅ appインスタンスをエクスポート
解決のポイントは3つです:
適切なオブジェクトのエクスポート - serverインスタンスからappインスタンスに変更し、supertestが期待するExpressアプリケーションを提供しました。
環境による条件分岐 - NODE_ENV=test
の時はサーバー起動をスキップし、テスト実行時の不要なサーバー起動を防止しました。
責任の分離の維持 - app.jsでアプリケーションロジック、server.jsでサーバー起動とテスト用エントリーポイントを分離しました。