9.8 KiB
9.8 KiB
Integration Testing with Testcontainers
Ollama Integration Test Setup
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.ollama.OllamaChatModel;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.AfterAll;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
@Testcontainers
class OllamaIntegrationTest {
@Container
static GenericContainer<?> ollama = new GenericContainer<>(
DockerImageName.parse("ollama/ollama:latest")
).withExposedPorts(11434);
private static ChatModel chatModel;
@BeforeAll
static void setup() {
chatModel = OllamaChatModel.builder()
.baseUrl(ollama.getEndpoint())
.modelName("llama2") // Use a lightweight model for testing
.temperature(0.0)
.timeout(java.time.Duration.ofSeconds(30))
.build();
}
@Test
void shouldGenerateResponseWithOllama() {
// Act
String response = chatModel.generate("What is 2 + 2?");
// Assert
assertNotNull(response);
assertFalse(response.trim().isEmpty());
assertTrue(response.contains("4") || response.toLowerCase().contains("four"));
}
@Test
void shouldHandleComplexQuery() {
// Act
String response = chatModel.generate(
"Explain the difference between ArrayList and LinkedList in Java"
);
// Assert
assertNotNull(response);
assertTrue(response.length() > 50);
assertTrue(response.toLowerCase().contains("arraylist"));
assertTrue(response.toLowerCase().contains("linkedlist"));
}
}
Embedding Store Integration Test
import dev.langchain4j.data.embedding.Embedding;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.ollama.OllamaEmbeddingModel;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
class EmbeddingStoreIntegrationTest {
private EmbeddingModel embeddingModel;
private EmbeddingStore<TextSegment> embeddingStore;
@BeforeEach
void setup() {
// Use in-memory store for faster tests
embeddingStore = new InMemoryEmbeddingStore();
// For production tests, you could use Testcontainers with Chroma/Weaviate
embeddingModel = OllamaEmbeddingModel.builder()
.baseUrl("http://localhost:11434")
.modelName("nomic-embed-text")
.build();
}
@Test
void shouldStoreAndRetrieveEmbeddings() {
// Arrange
TextSegment segment = TextSegment.from("Java is a programming language");
Embedding embedding = embeddingModel.embed(segment.text()).content();
// Act
String id = embeddingStore.add(embedding, segment);
// Assert
assertNotNull(id);
// Verify retrieval
var searchRequest = EmbeddingSearchRequest.builder()
.queryEmbedding(embedding)
.maxResults(1)
.build();
List<EmbeddingMatch<TextSegment>> matches = embeddingStore.search(searchRequest);
assertEquals(1, matches.size());
assertEquals(segment.text(), matches.get(0).embedded().text());
}
}
RAG Integration Test
import dev.langchain4j.data.document.Document;
import dev.langchain4j.data.document.DocumentSplitter;
import dev.langchain4j.data.document.splitter.ParagraphSplitter;
import dev.langchain4j.rag.content.retriever.ContentRetriever;
import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever;
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
class RagSystemTest {
private ContentRetriever contentRetriever;
private ChatModel chatModel;
@BeforeEach
void setup() {
// Setup embedding store
EmbeddingStore<TextSegment> embeddingStore = new InMemoryEmbeddingStore();
// Setup embedding model
EmbeddingModel embeddingModel = OllamaEmbeddingModel.builder()
.baseUrl("http://localhost:11434")
.modelName("nomic-embed-text")
.build();
// Setup content retriever
contentRetriever = EmbeddingStoreContentRetriever.builder()
.embeddingModel(embeddingModel)
.embeddingStore(embeddingStore)
.maxResults(3)
.build();
// Setup chat model
chatModel = OllamaChatModel.builder()
.baseUrl("http://localhost:11434")
.modelName("llama2")
.build();
// Ingest test documents
ingestTestDocuments(embeddingStore, embeddingModel);
}
private void ingestTestDocuments(EmbeddingStore<TextSegment> store, EmbeddingModel model) {
DocumentSplitter splitter = new ParagraphSplitter();
Document doc1 = Document.from("Spring Boot is a Java framework for building microservices");
Document doc2 = Document.from("Maven is a build automation tool for Java projects");
Document doc3 = Document.from("JUnit is a testing framework for Java applications");
List<Document> documents = List.of(doc1, doc2, doc3);
EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
.embeddingModel(model)
.embeddingStore(store)
.documentSplitter(splitter)
.build();
ingestor.ingest(documents);
}
@Test
void shouldRetrieveRelevantContent() {
// Arrange
RagAssistant assistant = AiServices.builder(RagAssistant.class)
.chatLanguageModel(chatModel)
.contentRetriever(contentRetriever)
.build();
// Act
String response = assistant.chat("What is Spring Boot?");
// Assert
assertNotNull(response);
assertTrue(response.toLowerCase().contains("spring boot"));
assertTrue(response.toLowerCase().contains("framework"));
}
interface RagAssistant {
String chat(String message);
}
}
Performance Testing
Response Time Test
import dev.langchain4j.model.chat.ChatModel;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
import java.time.Duration;
import java.time.Instant;
import static org.junit.jupiter.api.Assertions.*;
class PerformanceTest {
@Test
@Timeout(30)
void shouldRespondWithinTimeLimit() {
// Arrange
ChatModel model = OllamaChatModel.builder()
.baseUrl("http://localhost:11434")
.modelName("llama2")
.timeout(Duration.ofSeconds(20))
.build();
// Act
Instant start = Instant.now();
String response = model.generate("What is 2 + 2?");
Instant end = Instant.now();
// Assert
Duration duration = Duration.between(start, end);
assertTrue(duration.toSeconds() < 15, "Response took too long: " + duration);
assertNotNull(response);
}
}
Token Usage Tracking Test
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.output.TokenUsage;
@Test
void shouldTrackTokenUsage() {
// Arrange
ChatModel mockModel = mock(ChatModel.class);
var mockResponse = Response.from(
AiMessage.from("Response"),
new TokenUsage(10, 20, 30)
);
when(mockModel.generate(any(String.class)))
.thenReturn(mockResponse);
// Act
var response = mockModel.generate("Test query");
// Assert
assertEquals(10, response.tokenUsage().inputTokenCount());
assertEquals(20, response.tokenUsage().outputTokenCount());
assertEquals(30, response.tokenUsage().totalTokenCount());
}
Vector Store Integration Tests
Qdrant Integration Test
import dev.langchain4j.store.embedding.EmbeddingStore;
import dev.langchain4j.store.embedding.qdrant.QdrantEmbeddingStore;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
@Testcontainers
class QdrantIntegrationTest {
@Container
static GenericContainer<?> qdrant = new GenericContainer<>(
DockerImageName.parse("qdrant/qdrant:latest")
).withExposedPorts(6333);
private EmbeddingStore<TextSegment> embeddingStore;
@BeforeEach
void setup() {
var host = qdrant.getHost();
var port = qdrant.getFirstMappedPort();
embeddingStore = QdrantEmbeddingStore.builder()
.host(host)
.port(port)
.collectionName("test-collection")
.build();
}
@Test
void shouldStoreAndRetrieveVectors() {
// Arrange
var text = "Spring Boot is a Java framework";
var embeddingModel = createMockEmbeddingModel(text);
var segment = TextSegment.from(text);
// Act
String id = embeddingStore.add(embeddingModel.embed(text).content(), segment);
// Assert
assertNotNull(id);
var searchRequest = EmbeddingSearchRequest.builder()
.queryEmbedding(embeddingModel.embed(text).content())
.maxResults(1)
.build();
var result = embeddingStore.search(searchRequest);
assertEquals(1, result.matches().size());
}
}