Java library for integration testing with Docker containers
Docker network creation and management for container communication. Networks enable containers to discover and communicate with each other using network aliases and custom DNS names, supporting complex multi-container test scenarios.
Core interface for Docker network management with automatic cleanup support.
/**
* Represents a Docker network for container communication.
* Implements AutoCloseable for automatic cleanup.
*/
public interface Network extends AutoCloseable {
/**
* Create a new network with default settings.
* Convenience method that returns Network.builder().build().
*
* @return new network instance
*/
static Network newNetwork();
/**
* Get a builder for creating networks with custom configuration.
* Note: Returns NetworkImpl.NetworkImplBuilder which is the internal implementation.
* Use the builder methods to configure and call build() to get a Network instance.
*
* @return network builder (internal implementation type exposed for builder pattern)
*/
static NetworkImpl.NetworkImplBuilder builder();
/**
* Shared network instance for reuse across containers.
* Useful when multiple test classes need to share a network.
* Cannot be closed by user code - only ResourceReaper can clean it up.
*/
Network SHARED;
/**
* Get the Docker network ID.
*
* @return network ID
*/
String getId();
/**
* Close and remove the network.
* Called automatically when using try-with-resources.
*/
@Override
void close();
}Usage Examples:
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
import org.testcontainers.utility.DockerImageName;
// Create a new network
try (Network network = Network.newNetwork()) {
GenericContainer<?> database = new GenericContainer<>(DockerImageName.parse("postgres:15"))
.withNetwork(network)
.withNetworkAliases("db")
.withExposedPorts(5432);
GenericContainer<?> app = new GenericContainer<>(DockerImageName.parse("myapp:latest"))
.withNetwork(network)
.withEnv("DATABASE_HOST", "db") // Use network alias
.withEnv("DATABASE_PORT", "5432")
.withExposedPorts(8080);
database.start();
app.start();
// Containers can communicate using network aliases
// app can reach database at "db:5432"
} // Network automatically cleaned up
// Use shared network
GenericContainer<?> redis = new GenericContainer<>(DockerImageName.parse("redis:7.0"))
.withNetwork(Network.SHARED)
.withNetworkAliases("cache");Builder for creating networks with custom configuration. This builder is generated by Lombok's @Builder annotation and follows Lombok naming conventions.
/**
* Builder for creating custom Network instances with specific configuration.
* Generated by Lombok @Builder annotation. Method names follow Lombok conventions
* (field name without "with" prefix).
*/
public static class NetworkImplBuilder {
/**
* Set the network driver (e.g., "bridge", "overlay", "host").
* Default: "bridge"
*
* @param driver Network driver name
* @return Builder instance for chaining
*/
public NetworkImplBuilder driver(String driver);
/**
* Enable or disable IPv6 for the network.
* Default: null (Docker daemon default, typically disabled)
*
* @param enableIpv6 Boolean value - true to enable IPv6, false to disable, null for default
* @return Builder instance for chaining
*/
public NetworkImplBuilder enableIpv6(Boolean enableIpv6);
/**
* Add a single custom modifier for the CreateNetworkCmd. Allows advanced network configuration
* including labels, options, IPAM settings, and other Docker network settings.
*
* Can be called multiple times to add multiple modifiers (Lombok @Singular generates this method).
*
* Example usage for adding labels:
* .createNetworkCmdModifier(cmd -> cmd.withLabels(Map.of("env", "test")))
*
* @param createNetworkCmdModifier Consumer that modifies CreateNetworkCmd
* @return Builder instance for chaining
*/
public NetworkImplBuilder createNetworkCmdModifier(Consumer<CreateNetworkCmd> createNetworkCmdModifier);
/**
* Add multiple custom modifiers for the CreateNetworkCmd at once.
* Lombok @Singular annotation generates this plural form method.
*
* @param createNetworkCmdModifiers Collection of Consumers that modify CreateNetworkCmd
* @return Builder instance for chaining
*/
public NetworkImplBuilder createNetworkCmdModifiers(Collection<? extends Consumer<CreateNetworkCmd>> createNetworkCmdModifiers);
/**
* Build the Network instance with configured settings.
*
* @return Configured NetworkImpl instance
*/
public NetworkImpl build();
}
/**
* Implementation of Network interface. Uses Lombok @Getter annotation.
* Fields have automatically generated getter methods.
* Constructor is package-private/internal. Use Network.builder() to create instances.
*/
@Builder
@Getter
class NetworkImpl implements Network {
/**
* Get the network name (randomly generated UUID).
*
* @return network name
*/
public String getName();
/**
* Get the network ID (lazily initialized on first call).
* First call triggers network creation in Docker.
* Subsequent calls return the cached ID.
*
* @return network ID
*/
@Override
public String getId();
/**
* Get the IPv6 setting for this network.
* Lombok @Getter generates this method.
*
* @return Boolean value - true if IPv6 enabled, false if disabled, null if using default
*/
public Boolean getEnableIpv6();
/**
* Get the network driver.
* Lombok @Getter generates this method.
*
* @return network driver name (e.g., "bridge", "overlay")
*/
public String getDriver();
/**
* Get the collection of CreateNetworkCmd modifiers.
* Lombok @Getter generates this method.
*
* @return set of modifiers for custom network configuration
*/
public Set<Consumer<CreateNetworkCmd>> getCreateNetworkCmdModifiers();
/**
* Close and remove the network.
*/
@Override
public void close();
}Usage Examples:
import org.testcontainers.containers.Network;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.utility.DockerImageName;
// Create basic network using builder
Network network = Network.builder().build();
// Use the network
try (network) {
GenericContainer<?> container = new GenericContainer<>(DockerImageName.parse("alpine:latest"))
.withNetwork(network)
.withCommand("sleep", "infinity");
container.start();
} // Network cleaned up automatically
// Note: For most use cases, Network.newNetwork() is simpler and recommended
Network simpleNetwork = Network.newNetwork();Network aliases provide DNS names for containers within a network, enabling service discovery.
/**
* Set network aliases for the container.
* These become DNS names that other containers can use to reach this container.
*
* Part of GenericContainer API:
*/
public SELF withNetworkAliases(String... aliases);Usage Example:
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
import org.testcontainers.utility.DockerImageName;
Network network = Network.newNetwork();
// Database with multiple aliases
GenericContainer<?> database = new GenericContainer<>(DockerImageName.parse("postgres:15"))
.withNetwork(network)
.withNetworkAliases("db", "database", "postgres") // Multiple DNS names
.withEnv("POSTGRES_PASSWORD", "secret")
.withExposedPorts(5432);
// Cache with alias
GenericContainer<?> redis = new GenericContainer<>(DockerImageName.parse("redis:7.0"))
.withNetwork(network)
.withNetworkAliases("cache", "redis")
.withExposedPorts(6379);
// Application can reach services using any of their aliases
GenericContainer<?> app = new GenericContainer<>(DockerImageName.parse("myapp:latest"))
.withNetwork(network)
.withEnv("DATABASE_URL", "postgresql://postgres:5432/test") // Using alias
.withEnv("REDIS_URL", "redis://cache:6379") // Using alias
.withExposedPorts(8080);
database.start();
redis.start();
app.start();
// Inside the app container:
// - "db", "database", or "postgres" all resolve to the database container
// - "cache" or "redis" resolve to the Redis containerAlternative to custom networks - use predefined network modes.
/**
* Set the network mode for the container.
* Alternative to using Network objects.
*
* Part of GenericContainer API:
*/
public SELF withNetworkMode(String networkMode);Network Mode Values:
"bridge" - Default bridge network"host" - Use host network (container shares host's network stack)"none" - No network"container:<name|id>" - Share another container's network"<network-name>" - Connect to named networkUsage Examples:
// Use host network
GenericContainer<?> hostNetwork = new GenericContainer<>(DockerImageName.parse("nginx:alpine"))
.withNetworkMode("host"); // Container uses host's network directly
// Use bridge network (default)
GenericContainer<?> bridgeNetwork = new GenericContainer<>(DockerImageName.parse("redis:7.0"))
.withNetworkMode("bridge");
// Share another container's network
GenericContainer<?> sidecar = new GenericContainer<>(DockerImageName.parse("alpine:latest"))
.withNetworkMode("container:" + mainContainer.getContainerId());
// Connect to existing network by name
GenericContainer<?> existing = new GenericContainer<>(DockerImageName.parse("postgres:15"))
.withNetworkMode("my-existing-network");import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.utility.DockerImageName;
import java.time.Duration;
public class MultiContainerNetworkTest {
@Test
public void testApplicationWithDependencies() {
// Create shared network
try (Network network = Network.newNetwork()) {
// PostgreSQL database
GenericContainer<?> postgres = new GenericContainer<>(
DockerImageName.parse("postgres:15"))
.withNetwork(network)
.withNetworkAliases("postgres", "db")
.withEnv("POSTGRES_DB", "appdb")
.withEnv("POSTGRES_USER", "appuser")
.withEnv("POSTGRES_PASSWORD", "secret")
.withExposedPorts(5432)
.waitingFor(Wait.forListeningPort()
.withStartupTimeout(Duration.ofSeconds(60)));
// Redis cache
GenericContainer<?> redis = new GenericContainer<>(
DockerImageName.parse("redis:7.0-alpine"))
.withNetwork(network)
.withNetworkAliases("redis", "cache")
.withExposedPorts(6379)
.waitingFor(Wait.forListeningPort());
// RabbitMQ message broker
GenericContainer<?> rabbitmq = new GenericContainer<>(
DockerImageName.parse("rabbitmq:3-management-alpine"))
.withNetwork(network)
.withNetworkAliases("rabbitmq", "mq")
.withExposedPorts(5672, 15672)
.waitingFor(Wait.forListeningPort());
// Application container
GenericContainer<?> app = new GenericContainer<>(
DockerImageName.parse("myapp:latest"))
.withNetwork(network)
.withNetworkAliases("app")
.withEnv("DATABASE_URL", "postgresql://appuser:secret@postgres:5432/appdb")
.withEnv("REDIS_URL", "redis://cache:6379")
.withEnv("RABBITMQ_URL", "amqp://rabbitmq:5672")
.withExposedPorts(8080)
.dependsOn(postgres, redis, rabbitmq)
.waitingFor(Wait.forHttp("/health")
.forStatusCode(200)
.withStartupTimeout(Duration.ofMinutes(2)));
// Start all containers (dependencies start automatically)
app.start();
// All containers can communicate using their network aliases
String appUrl = String.format("http://%s:%d",
app.getHost(), app.getMappedPort(8080));
// Run tests against the application
// ...
} // Network and all containers cleaned up automatically
}
}import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
import org.testcontainers.lifecycle.Startables;
import org.testcontainers.utility.DockerImageName;
public class MicroservicesTest {
@Test
public void testMicroservicesCommunication() {
Network network = Network.newNetwork();
// Service registry
GenericContainer<?> consul = new GenericContainer<>(
DockerImageName.parse("consul:1.15"))
.withNetwork(network)
.withNetworkAliases("consul", "service-registry")
.withExposedPorts(8500);
// User service
GenericContainer<?> userService = new GenericContainer<>(
DockerImageName.parse("user-service:latest"))
.withNetwork(network)
.withNetworkAliases("user-service")
.withEnv("CONSUL_URL", "http://consul:8500")
.withExposedPorts(8081)
.dependsOn(consul);
// Order service
GenericContainer<?> orderService = new GenericContainer<>(
DockerImageName.parse("order-service:latest"))
.withNetwork(network)
.withNetworkAliases("order-service")
.withEnv("CONSUL_URL", "http://consul:8500")
.withEnv("USER_SERVICE_URL", "http://user-service:8081")
.withExposedPorts(8082)
.dependsOn(consul, userService);
// API Gateway
GenericContainer<?> gateway = new GenericContainer<>(
DockerImageName.parse("api-gateway:latest"))
.withNetwork(network)
.withNetworkAliases("gateway")
.withEnv("CONSUL_URL", "http://consul:8500")
.withExposedPorts(8080)
.dependsOn(consul, userService, orderService);
// Start all services
Startables.deepStart(gateway).join();
// Services can discover each other via Consul
// Order service can call user service using network alias
String gatewayUrl = String.format("http://%s:%d",
gateway.getHost(), gateway.getMappedPort(8080));
// Test API calls through gateway
}
}import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
import org.testcontainers.utility.DockerImageName;
// Shared infrastructure for all tests
public class TestInfrastructure {
// Shared network used by all test classes
public static final Network SHARED_NETWORK = Network.SHARED;
// Shared database for all tests
public static final GenericContainer<?> POSTGRES = new GenericContainer<>(
DockerImageName.parse("postgres:15"))
.withNetwork(SHARED_NETWORK)
.withNetworkAliases("shared-db")
.withEnv("POSTGRES_PASSWORD", "test")
.withExposedPorts(5432);
static {
POSTGRES.start();
}
}
// Test class 1
public class UserServiceTest {
@Test
public void testUserService() {
GenericContainer<?> userService = new GenericContainer<>(
DockerImageName.parse("user-service:latest"))
.withNetwork(TestInfrastructure.SHARED_NETWORK)
.withEnv("DB_HOST", "shared-db")
.withExposedPorts(8081);
userService.start();
// Test uses shared database
}
}
// Test class 2
public class OrderServiceTest {
@Test
public void testOrderService() {
GenericContainer<?> orderService = new GenericContainer<>(
DockerImageName.parse("order-service:latest"))
.withNetwork(TestInfrastructure.SHARED_NETWORK)
.withEnv("DB_HOST", "shared-db")
.withExposedPorts(8082);
orderService.start();
// Test also uses shared database
}
}Advanced network configuration using the builder with custom modifiers.
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
import org.testcontainers.utility.DockerImageName;
import com.github.dockerjava.api.command.CreateNetworkCmd;
import java.util.Map;
public class CustomNetworkTest {
@Test
public void testWithCustomNetworkSettings() {
// Create network with custom driver
Network customNetwork = Network.builder()
.driver("bridge")
.enableIpv6(false)
.build();
try (Network network = customNetwork) {
GenericContainer<?> container1 = new GenericContainer<>(
DockerImageName.parse("alpine:latest"))
.withNetwork(network)
.withNetworkAliases("service-a")
.withCommand("sleep", "infinity");
GenericContainer<?> container2 = new GenericContainer<>(
DockerImageName.parse("alpine:latest"))
.withNetwork(network)
.withNetworkAliases("service-b")
.withCommand("sleep", "infinity");
container1.start();
container2.start();
// Test network connectivity
Container.ExecResult result = container1.execInContainer(
"ping", "-c", "1", "service-b");
assertEquals(0, result.getExitCode());
}
}
@Test
public void testWithAdvancedNetworkSettings() {
// Use createNetworkCmdModifier for advanced configuration like labels and options
Network advancedNetwork = Network.builder()
.driver("bridge")
.createNetworkCmdModifier(cmd -> {
// Add custom labels
cmd.withLabels(Map.of(
"test.suite", "integration",
"test.environment", "custom"
));
})
.createNetworkCmdModifier(cmd -> {
// Add custom options (MTU, bridge name, etc.)
cmd.withOptions(Map.of(
"com.docker.network.bridge.name", "testcontainers-custom",
"com.docker.network.driver.mtu", "1450"
));
})
.build();
try (Network network = advancedNetwork) {
GenericContainer<?> container = new GenericContainer<>(
DockerImageName.parse("alpine:latest"))
.withNetwork(network)
.withCommand("sleep", "infinity");
container.start();
// Network has custom labels and options applied
}
}
@Test
public void testWithIPAMConfiguration() {
// Configure custom IP Address Management (IPAM) settings
Network ipamNetwork = Network.builder()
.driver("bridge")
.createNetworkCmdModifier(cmd -> {
// Configure IPAM with custom subnet and gateway
cmd.withIpamConfig(
// IPAM configuration with specific subnet and gateway
new IPAM()
.withDriver("default")
.withConfig(new IPAMConfig()
.withSubnet("172.20.0.0/16")
.withGateway("172.20.0.1")
)
);
})
.build();
try (Network network = ipamNetwork) {
// Containers in this network use the custom subnet
GenericContainer<?> db = new GenericContainer<>(
DockerImageName.parse("postgres:15"))
.withNetwork(network)
.withNetworkAliases("database");
db.start();
// Database is on 172.20.0.0/16 subnet
}
}
@Test
public void testWithEnableIPv6() {
// Enable IPv6 on the network
Network ipv6Network = Network.builder()
.driver("bridge")
.enableIpv6(true)
.createNetworkCmdModifier(cmd -> {
// Configure IPv6 CIDR
cmd.withIpamConfig(
new IPAM()
.withDriver("default")
.withConfig(new IPAMConfig()
.withSubnet("2001:db8::/32")
)
);
})
.build();
try (Network network = ipv6Network) {
GenericContainer<?> container = new GenericContainer<>(
DockerImageName.parse("alpine:latest"))
.withNetwork(network)
.withCommand("sleep", "infinity");
container.start();
// Container has both IPv4 and IPv6 addresses
}
}
}Use custom networks when:
Use network modes when:
// Always use try-with-resources for automatic cleanup
try (Network network = Network.newNetwork()) {
// Use network
} // Automatically cleaned up
// Or manually manage lifecycle
Network network = Network.newNetwork();
try {
// Use network
} finally {
network.close();
}// Create separate networks for isolation
public class IsolatedNetworkTest {
@Test
public void testServiceIsolation() {
// Network A - Services that should communicate
try (Network networkA = Network.newNetwork()) {
GenericContainer<?> serviceA1 = createService(networkA, "service-a1");
GenericContainer<?> serviceA2 = createService(networkA, "service-a2");
// Network B - Isolated services
try (Network networkB = Network.newNetwork()) {
GenericContainer<?> serviceB1 = createService(networkB, "service-b1");
GenericContainer<?> serviceB2 = createService(networkB, "service-b2");
// Services in A can communicate with each other
// Services in B can communicate with each other
// Services in A cannot reach services in B (and vice versa)
}
}
}
}Complete API reference for network-related methods in GenericContainer.
/**
* Network configuration methods in GenericContainer.
*/
public class GenericContainer<SELF extends GenericContainer<SELF>> {
/**
* Set the network for this container.
*
* @param network the network to use
* @return this container for method chaining
*/
public SELF withNetwork(Network network);
/**
* Get the network for this container.
*
* @return the network, or null if not set
*/
public Network getNetwork();
/**
* Set the network for this container.
*
* @param network the network to use
*/
public void setNetwork(Network network);
/**
* Set the network mode for this container.
*
* @param networkMode the network mode (e.g., "bridge", "host", "none", or "container:<name|id>")
* @return this container for method chaining
*/
public SELF withNetworkMode(String networkMode);
/**
* Get the network mode for this container.
*
* @return the network mode string
*/
public String getNetworkMode();
/**
* Set the network mode for this container.
*
* @param networkMode the network mode to use
*/
public void setNetworkMode(String networkMode);
/**
* Set network aliases for this container.
* These become DNS names that other containers on the same network can use.
*
* @param aliases one or more network aliases
* @return this container for method chaining
*/
public SELF withNetworkAliases(String... aliases);
/**
* Get the network aliases for this container.
*
* @return list of network aliases
*/
public List<String> getNetworkAliases();
/**
* Set the network aliases for this container.
*
* @param aliases list of network aliases
*/
public void setNetworkAliases(List<String> aliases);
}Install with Tessl CLI
npx tessl i tessl/maven-org-testcontainers--testcontainersdocs