Overview
Create Testcontainers infrastructure to replace Mockito mocks with real production code for better test coverage and lower maintenance.
Priority: HIGH
Estimated Time: Week 1
Context
After analyzing both approaches (see PHASE1_COMPARISON.md), we chose Testcontainers + Real Production Code instead of in-memory stubs because:
- ✅ Lower implementation cost (5h vs 10h)
- ✅ Better bug detection (catches SQL errors, schema issues, vector index config)
- ✅ Less code to maintain (~50 lines vs ~200 lines)
- ✅ Reuses production code (
ContentPersistenceAdapter, ArcadeContentRepository)
Tasks
1.1 Create ArcadeDB Testcontainer
File: src/test/java/it/robfrank/linklift/testcontainers/ArcadeDbContainer.java
Create a reusable Testcontainer for ArcadeDB that handles:
- Database lifecycle management
- Schema initialization (Content vertex type, vector index)
- Wait strategy for container readiness
- Helper methods for database creation and cleanup
Key Features:
- Vector index:
LSM_TREE METRIC COSINE DIMENSIONS 384
- Exposes methods:
getHttpUrl(), getRootPassword(), createDatabase(), cleanDatabase()
1.2 Create Base Test Class
File: src/test/java/it/robfrank/linklift/testcontainers/ArcadeDbTestBase.java
Abstract base class that:
- Manages shared Testcontainer lifecycle (
@Container static field)
- Sets up real
ContentPersistenceAdapter and ArcadeContentRepository in @BeforeEach
- Cleans database between tests in
@AfterEach
- Provides
repository field for test classes
1.3 Create FakeEmbeddingGenerator
File: src/test/java/it/robfrank/linklift/adapter/out/ai/FakeEmbeddingGenerator.java
Deterministic fake implementation to replace mocked EmbeddingGenerator:
- Generates consistent 384-dimensional embeddings based on text hash
- Provides test helpers:
throwOnNextCall(), clearCache(), getCacheSize()
- No randomness - same text always produces same embedding
1.4 Update Dependencies
File: pom.xml
Add dependencies:
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>1.19.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>1.19.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<version>4.2.0</version>
<scope>test</scope>
</dependency>
1.5 Verify Infrastructure
Success Criteria
Related
- See
PHASE1_COMPARISON.md for detailed analysis
- See
TEST_REFACTORING_PLAN.md for full plan
- Blocks: Phase 2 (Refactor Service Tests)
Overview
Create Testcontainers infrastructure to replace Mockito mocks with real production code for better test coverage and lower maintenance.
Priority: HIGH
Estimated Time: Week 1
Context
After analyzing both approaches (see
PHASE1_COMPARISON.md), we chose Testcontainers + Real Production Code instead of in-memory stubs because:ContentPersistenceAdapter,ArcadeContentRepository)Tasks
1.1 Create ArcadeDB Testcontainer
File:
src/test/java/it/robfrank/linklift/testcontainers/ArcadeDbContainer.javaCreate a reusable Testcontainer for ArcadeDB that handles:
Key Features:
LSM_TREE METRIC COSINE DIMENSIONS 384getHttpUrl(),getRootPassword(),createDatabase(),cleanDatabase()1.2 Create Base Test Class
File:
src/test/java/it/robfrank/linklift/testcontainers/ArcadeDbTestBase.javaAbstract base class that:
@Containerstatic field)ContentPersistenceAdapterandArcadeContentRepositoryin@BeforeEach@AfterEachrepositoryfield for test classes1.3 Create FakeEmbeddingGenerator
File:
src/test/java/it/robfrank/linklift/adapter/out/ai/FakeEmbeddingGenerator.javaDeterministic fake implementation to replace mocked
EmbeddingGenerator:throwOnNextCall(),clearCache(),getCacheSize()1.4 Update Dependencies
File:
pom.xmlAdd dependencies:
1.5 Verify Infrastructure
Success Criteria
ArcadeDbContainerstarts and initializes schemaArcadeDbTestBaseprovides workingrepositoryfieldFakeEmbeddingGeneratorproduces deterministic embeddingsRelated
PHASE1_COMPARISON.mdfor detailed analysisTEST_REFACTORING_PLAN.mdfor full plan