0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

デプロイのためテスト環境導入したがsupertest で app.address is not a function が出た

Posted at

デプロイのためテスト環境導入したが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でサーバー起動とテスト用エントリーポイントを分離しました。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?