Testcontainers#
The docling-testcontainers module provides a ready-to-use Testcontainers integration for running a Docling Serve instance in your tests. It wraps the official container image and exposes a simple Java API so you can spin up Docling as part of your JUnit test lifecycle and exercise client code against a real server.
If you need to talk to a running server from your application code, pair this module with the reference HTTP client:
- docling-serve-client
When to use this module#
- You want end-to-end tests that run against a real Docling Serve in Docker.
- You need a portable, reliable way to boot Docling Serve on CI without managing it yourself.
- You want a convenient Java API to tweak the container image, environment variables, startup timeout, and optional UI.
Installation#
Add the Testcontainers module to your test dependencies.
dependencies {
testImplementation("ai.docling:docling-testcontainers:0.1.5")
}
<dependencies>
<dependency>
<groupId>ai.docling</groupId>
<artifactId>docling-testcontainers</artifactId>
<version>0.1.5</version>
<scope>test</scope>
</dependency>
</dependencies>
Quick start#
Spin up Docling Serve with JUnit 5 and run a simple health check using the reference client.
import static org.assertj.core.api.Assertions.assertThat;
import java.net.URI;
import org.junit.jupiter.api.Test;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import ai.docling.api.serve.DoclingServeApi;
import ai.docling.api.serve.health.HealthCheckResponse;
import ai.docling.client.serve.DoclingServeClientBuilderFactory;
import ai.docling.testcontainers.serve.DoclingServeContainer;
import ai.docling.testcontainers.serve.config.DoclingServeContainerConfig;
@Testcontainers
class DoclingContainerSmokeTest {
@Container
private final DoclingServeContainer docling = new DoclingServeContainer(
DoclingServeContainerConfig.builder()
.image(DoclingServeContainerConfig.DOCLING_IMAGE)
.enableUi(true)
.build()
);
@Test
void health_is_ok() {
String base = "http://" + docling.getHost() + ":" + docling.getPort();
DoclingServeApi api = DoclingServeClientBuilderFactory
.newBuilder()
.baseUrl(base)
.build();
HealthCheckResponse health = api.health();
assertThat(health.getStatus()).isNotBlank();
}
}
Note
@Containermanages container lifecycle for you. Use astaticfield to reuse the container across tests in the class.getHost()andgetPort()are provided by Testcontainers/GenericContainer;getPort()maps the container’s internal port to a random free host port.
Using it with the reference client for conversions#
Once the container is up, you can call the Convert endpoint through docling-serve-client:
import java.net.URI;
import ai.docling.api.serve.convert.request.ConvertDocumentRequest;
import ai.docling.api.serve.convert.request.options.ConvertDocumentOptions;
import ai.docling.api.serve.convert.request.options.OutputFormat;
import ai.docling.api.serve.convert.request.source.HttpSource;
import ai.docling.api.serve.convert.request.target.InBodyTarget;
import ai.docling.api.serve.convert.response.ConvertDocumentResponse;
String baseUrl = "http://" + docling.getHost() + ":" + docling.getPort();
DoclingServeApi api = DoclingServeClientBuilderFactory.newBuilder().baseUrl(baseUrl).build();
ConvertDocumentRequest request = ConvertDocumentRequest.builder()
.source(HttpSource.builder().url(URI.create("https://arxiv.org/pdf/2408.09869")).build())
.options(ConvertDocumentOptions.builder()
.toFormat(OutputFormat.MARKDOWN)
.includeImages(true)
.build())
.target(InBodyTarget.builder().build())
.build();
ConvertDocumentResponse response = api.convertSource(request);
// Assert on response.getDocument().getMarkdownContent(), errors, timings, etc.
Configuration#
The container is configured via DoclingServeContainerConfig. Use its fluent builder to customize:
- Container image (default points to the official GHCR image)
- Whether to enable the demonstration UI
- Additional environment variables
- Startup timeout
import java.time.Duration;
import java.util.Map;
import ai.docling.testcontainers.serve.config.DoclingServeContainerConfig;
import ai.docling.testcontainers.serve.DoclingServeContainer;
DoclingServeContainerConfig config = DoclingServeContainerConfig.builder()
// Override the image if you need a different tag or registry
.image("ghcr.io/docling-project/docling-serve:v1.8.0")
// Enable the optional web UI served by Docling Serve
.enableUi(true)
// Pass environment variables to fine‑tune behavior
.containerEnv(Map.of(
// Example: configure OCR languages or pipeline hints if supported by the server
"DOCLING_OCR_LANG", "eng,deu"
))
// Increase startup timeout if your CI is slow to pull images
.startupTimeout(Duration.ofMinutes(2))
.build();
DoclingServeContainer container = new DoclingServeContainer(config);
Defaults#
- Default internal port:
5001(exposed and mapped automatically) - Default image:
ghcr.io/docling-project/docling-serve:<version> - Default startup timeout: 1 minute
Tips and caveats#
- A container runtime (Docker/Podman) must be available to the test process (locally or on CI). For GitHub Actions, consider the official Testcontainers setup docs.
- Prefer
staticcontainers for faster test suites; or use reusability where applicable per Testcontainers guidelines. - If you run multiple containers, consider a shared
@Testcontainerstest base to avoid repeated pulls. - For plain
http://base URLs, the reference client forces HTTP/1.1 to interoperate smoothly with FastAPI. - Clean up resources: JUnit/Testcontainers manages lifecycle automatically for annotated containers. If you manage containers manually, remember to call
start()/stop().
Related modules#
- API types and request model:
docling-serve-api - Reference HTTP client:
docling-serve-client