langchain4j-testing-strategies について
LangChain4j を使う Java アプリケーション開発者向けのテスト戦略スキルです。AI Services、RAG ワークフロー、ツール実行を対象に、モデルのモック、Testcontainers による統合テスト、エンドツーエンド検証を扱います。
主な機能
- 01モデルのモックを使った単体テスト
- 02Testcontainers による実サービスのテスト
- 03RAG ワークフローとツール実行の検証
- 04ストリーミング、メモリ、エラー処理のテスト
- 05依存関係設定とテスト手順の参照
活用シーン
- 01LangChain4j AI Services の分離テスト
- 02コンテナ化モデル統合の検証
- 03RAG 検索チェーンのテスト
- 04ツール実行時のエラー処理確認
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ giuseppe-trisciuoglio/ developer-kit --skill langchain4j-testing-strategiesインストール後、Claude Code で/langchain4j-testing-strategiesを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/advanced-testing.mdintegration-testing.mdtesting-dependencies.mdunit-testing.mdworkflow-patterns.md詳細
LangChain4J のテスト戦略
概要
モックを使った単体テスト、Testcontainers を使った統合テスト、RAG システム、AI Services、ツール実行のエンドツーエンド検証のパターンです。
使用する場面
- AI サービスの単体テスト:LangChain4j AiServices を使用するサービスを、すばやく分離してテストする必要がある場合
- LangChain4j コンポーネントの統合テスト:Testcontainers を使用して実際の ChatModel、EmbeddingModel、RAG パイプラインをテストする場合
- AI モデルのモック化:外部 API を呼び出さずに、決定論的な応答を得る必要がある場合
- LLM ベースの Java アプリケーションのテスト:RAG ワークフロー、ツール実行、検索チェーンを検証する場合
手順
1. モックを使った単体テスト
すばやく分離してテストするには、モックモデルを使用します。references/unit-testing.md を参照してください。
ChatModel mockModel = mock(ChatModel.class);
when(mockModel.generate(any(String.class)))
.thenReturn(Response.from(AiMessage.from("Mocked response")));
var service = AiServices.builder(AiService.class)
.chatModel(mockModel)
.build();
2. テスト依存関係の設定
Maven/Gradle の依存関係を設定します。references/testing-dependencies.md を参照してください。
langchain4j-test- ガードレールのアサーションtestcontainers- コンテナ化されたテストmockito- 外部依存関係のモック化assertj- 流れるようなアサーション
3. Testcontainers を使った統合テスト
実際のサービスを使ってテストします。references/integration-testing.md を参照してください。
@Testcontainers
class OllamaIntegrationTest {
@Container
static GenericContainer<?> ollama = new GenericContainer<>(
DockerImageName.parse("ollama/ollama:0.5.4")
).withExposedPorts(11434);
@Test
void shouldGenerateResponse() {
// Verify container is healthy
assertTrue(ollama.isRunning());
await().atMost(30, TimeUnit.SECONDS)
.until(() -> ollama.getLogs().contains("API server listening"));
ChatModel model = OllamaChatModel.builder()
.baseUrl(ollama.getEndpoint())
.build();
// Verify model responds before running tests
assertDoesNotThrow(() -> model.generate("ping"));
String response = model.generate("Test query");
assertNotNull(response);
}
}
4. 高度な機能
ストリーミング、メモリ、エラー処理のパターンについては、references/advanced-testing.md を参照してください。
5. テストワークフロー
references/workflow-patterns.md のテストピラミッドに従います。
- 単体テスト 70%:モックを使ったすばやく分離されたテスト
- 統合テスト 20%:ヘルスチェックを行う実際のサービス
- エンドツーエンドテスト 10%:ワークフロー全体のテスト
70% Unit Tests ─ Mock ChatModel, guardrails, edge cases
20% Integration Tests ─ Testcontainers, vector stores, RAG
10% End-to-End Tests ─ Complete user journeys
トラブルシューティング
- コンテナが起動しない:Docker デーモンが実行中か確認し、イメージの存在を確認して、タイムアウトを延長します
- モデルが応答しない:baseUrl が正しいことを確認し、コンテナログを確認して、モデルが読み込まれていることを確認します
- テストがタイムアウトする:応答が遅いモデルでは
@Timeoutの時間を延長し、コンテナのリソース制限を確認します - 不安定なテスト:再試行ロジックを追加するか、アサーションの前にヘルスチェックを行います
例
単体テスト
@Test
void shouldProcessQueryWithMock() {
ChatModel mockModel = mock(ChatModel.class);
when(mockModel.generate(any(String.class)))
.thenReturn(Response.from(AiMessage.from("Test response")));
var service = AiServices.builder(AiService.class)
.chatModel(mockModel)
.build();
String result = service.chat("What is Java?");
assertEquals("Test response", result);
}
Testcontainers を使った統合テスト
@Testcontainers
class RAGIntegrationTest {
@Container
static GenericContainer<?> ollama = new GenericContainer<>(
DockerImageName.parse("ollama/ollama:0.5.4")
);
@BeforeAll
static void waitForContainerReady() {
await().atMost(60, TimeUnit.SECONDS)
.until(() -> ollama.getLogs().contains("API server listening"));
}
@Test
void shouldCompleteRAGWorkflow() {
assertTrue(ollama.isRunning());
var chatModel = OllamaChatModel.builder()
.baseUrl(ollama.getEndpoint())
.build();
var embeddingModel = OllamaEmbeddingModel.builder()
.baseUrl(ollama.getEndpoint())
.build();
var store = new InMemoryEmbeddingStore<>();
var retriever = EmbeddingStoreContentRetriever.builder()
.chatModel(chatModel)
.embeddingStore(store)
.embeddingModel(embeddingModel)
.build();
var assistant = AiServices.builder(RagAssistant.class)
.chatLanguageModel(chatModel)
.contentRetriever(retriever)
.build();
String response = assistant.chat("What is Spring Boot?");
assertNotNull(response);
assertTrue(response.contains("Spring"));
}
}
ベストプラクティス
- テストを分離するため、
@BeforeEach/@AfterEachを使用します - 単体テストでは実際の API を呼び出さず、モックを使用します
- 外部サービスの呼び出しには
@Timeoutを含めます - 成功時とエラー処理の両方のシナリオをテストします
- 応答の一貫性とエッジケースを検証します
よくあるパターン
モック戦略
ChatModel mockModel = mock(ChatModel.class);
when(mockModel.generate(anyString())).thenReturn(Response.from(AiMessage.from("Mocked")));
when(mockModel.generate(eq("Hello"))).thenReturn(Response.from(AiMessage.from("Hi")));
when(mockModel.generate(contains("Java"))).thenReturn(Response.from(AiMessage.from("Java")));
アサーションヘルパー
assertThat(response).isNotNull().isNotEmpty();
assertThat(response).containsAll(expectedKeywords);
assertThat(response).doesNotContain("error");
参考ドキュメント
- テスト依存関係 - Maven/Gradle の設定
- 単体テスト - モックモデル、ガードレール
- 統合テスト - Testcontainers、実際のサービス
- 高度なテスト - ストリーミング、メモリ、エラー処理
- ワークフローパターン - テストピラミッド、ベストプラクティス
制約と警告
- AI の応答は非決定論的です。信頼性の高い単体テストにはモックを使用します
- コストやレート制限を避けるため、テストで実際の API 呼び出しを行わないでください
- 統合テストには Docker が必要です。コンテナのヘルスチェックを使用します
- RAG テストでは、埋め込みストアに適切なデータを事前に格納する必要があります
- モックベースのテストでは実際の LLM の動作を保証できないため、統合テストも併用します
- テスト専用の設定プロファイルを使用し、本番データには決して影響を与えないでください
コメント
Markdown 対応