メインコンテンツまでスキップ

Integration Testing

RedisやPostgreSQLのような外部サービスを必要とするintegration testには、Testcontainersを使います。Zeltは、lifecycleシステムと統合された、事前設定済みのcontainer configを提供します。

インストール

pnpm add -D @zeltjs/testing testcontainers

Redis Integration Testing

describe('CacheService', () => {
  it('should cache values in Redis', async () => {
    const { target } = await createTestTarget(CacheService, {
      configs: [RedisTestContainerConfig],
    });

    await target.set('key', 'value');
    const result = await target.get('key');
    
    expect(result).toBe('value');
  });
});

RedisTestContainerConfig は自動的に次を行います。

  • テスト前にRedis containerを起動する
  • RedisConfig に依存するサービスへ接続URLを提供する
  • テスト後にcontainerを停止・クリーンアップする

Custom Container Config

Lifecycle interfaceを実装して、独自のcontainer configを作成します。

@Config
export class PostgresTestContainerConfig implements Lifecycle {
  private container: StartedTestContainer | undefined;
  private connectionUrl = '';

  constructor(lifecycle = inject(LifecycleManager)) {
    lifecycle.register(this);
  }

  async startup(): Promise<void> {
    this.container = await new GenericContainer('postgres:16-alpine')
      .withEnvironment({
        POSTGRES_USER: 'test',
        POSTGRES_PASSWORD: 'test',
        POSTGRES_DB: 'testdb',
      })
      .withExposedPorts(5432)
      .start();

    const host = this.container.getHost();
    const port = this.container.getMappedPort(5432);
    this.connectionUrl = `postgres://test:test@${host}:${port}/testdb`;
  }

  async shutdown(): Promise<void> {
    await this.container?.stop();
  }

  get url(): string {
    return this.connectionUrl;
  }
}

Sociable Unit Tests

Testcontainersを使ったintegration testは、モックではなく実際の依存関係と連携するunitをテストする「Sociable Unit Tests」に最適です。

describe('SessionService with real Redis', () => {
  it('should persist session across service calls', async () => {
    const { target, get } = await createTestTarget(SessionService, {
      configs: [RedisTestContainerConfig],
    });

    const userService = get(UserService);
    const session = await target.create({ userId: '123' });
    
    const user = await userService.fromSession(session.id);
    expect(user.id).toBe('123');
  });
});