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');
});
});