I develop integration tests for my spring boot application, which works with Cassandra. I use CassandraTemplate
for communication with Cassandra.
I have the following config for the database src/test/resources/application.properties:
spring.data.cassandra.contact-points=cassandra-host
spring.data.cassandra.port=9042
To create Testcontainers
with Cassandra I try 2 ways:
1) https://niels.nu/blog/2017/spring-cassandra-integration-tests.html
@ActiveProfiles("test")
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@SpringBootTest(classes = {ExampleApplication.class})
@ContextConfiguration(initializers = CounterIntegrationTestContainers.Initializer.class)
@EnableConfigurationProperties
public class CounterIntegrationTestContainers extends CounterIntegrationTest {
@ClassRule
public static GenericContainer cassandra =
new GenericContainer("cassandra:3")
.withExposedPorts(9042);
public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
EnvironmentTestUtils.addEnvironment(
"testcontainers",
configurableApplicationContext.getEnvironment(),
"cassandra.host=" + cassandra.getContainerIpAddress(),
"cassandra.port=" + cassandra.getMappedPort(9042)
);
}
}
}
2) https://www.baeldung.com/spring-boot-testcontainers-integration-test - in this example we can see postgresql container, but I change it to Cassandra:
public class BaeldungPostgresqlContainer extends PostgreSQLContainer<BaeldungPostgresqlContainer> {
private static final String IMAGE_VERSION = "postgres:11.1";
private static BaeldungPostgresqlContainer container;
private BaeldungPostgresqlContainer() {
super(IMAGE_VERSION);
}
public static BaeldungPostgresqlContainer getInstance() {
if (container == null) {
container = new BaeldungPostgresqlContainer();
}
return container;
}
@Override
public void start() {
super.start();
System.setProperty("DB_URL", container.getJdbcUrl());
System.setProperty("DB_USERNAME", container.getUsername());
System.setProperty("DB_PASSWORD", container.getPassword());
}
@Override
public void stop() {
//do nothing, JVM handles shut down
}
}
So, I have a problem. When I start tests, I got cannot create CassandraTemplate
bean, because Cassandra server is not available. it seems, that Spring Data tries to health check Cassandra before creating of test bean of the database server.
Is there any way to use Testcontainers Cassandra with Spring Data for Apache Cassandra?
It seems, that I can run tests with such class:
@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(
initializers = CassandraTestPrjApplicationTests.Initializer.class
)
public class CassandraTestPrjApplicationTests {
@Test
public void contextLoads() {
}
public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
GenericContainer<?> cassandra =
new GenericContainer<>("cassandra:3").withExposedPorts(9042);
cassandra.start();
TestPropertyValues.of(
"spring.data.cassandra.contact-points=" + cassandra.getContainerIpAddress(),
"spring.data.cassandra.port=" + cassandra.getMappedPort(9042)
).applyTo(applicationContext);
}
}
}
and here is my gradle.build:
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-cassandra'
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testCompile "org.testcontainers:testcontainers:1.12.0"
testCompile "org.testcontainers:cassandra:1.12.0"
}
Considering the first approach, I'd start with checking the container that is running during the test execution: docker ps
and see if it starts (i.e. docker daemon is up) and exposes the correct port.
Then try to telnet
to the corresponding host/port to make sure that service starts during the default 60 seconds timeout period.
It seems enough for the container to start, but if telnet
does not connect during this period, try to increase it like
new GenericContainer("cassandra:3")
.withExposedPorts(9042)
.withStartupTimeout(Duration.ofMinutes(2));
If the container exposes the correct port, but the test does not connect to it,
make sure you use the correct configuration parameters in your test. I see the usage of spring.data.cassandra.contact-points
, the example you've sent uses a bit different configuration, check if you the correct configuration parameter in your cluster initialization code (e.g. "${contact-points}"
instead of "${container.host}"
or vice versa).
One more option to check your integration test logic works as expected (and there's something wrong with testcontainers configuration) is to start Cassandra container and hardcode it's host and port before running the test.
Hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With