I am using Spring Boot and Spring Data Cassandra in my webflux application. I have issue when I do integration test with docker by using testcontainer, Spring doesn't inject the implementation of my cassandra repository in my tests but it always injects Mockito mock object.
For testing I have 2 kind of tests are unitTest and integrationTest with properly profile test and integration.
Below are all my required classes and test classes
My cassandra repository using Spring Data Cassandra
@Repository
public interface UserGroupRepository extends CassandraRepository<UserGroup, String> {
}
For test profile
@ActiveProfiles("test")
@Configuration
public class TestConfig {
@MockBean
private CqlSession cassandraSession;
@MockBean
private CassandraConverter cassandraConverter;
@MockBean
public UserGroupRepository consumerSegmentRepository;
@MockBean
private CassandraMappingContext cassandraMapping;
@MockBean
private SessionFactoryFactoryBean cassandraSessionFactory;
@MockBean
private CassandraAdminTemplate cassandraAdminTemplate;
@MockBean
private SessionFactory sessionFactory;
}
For integration profile
My base integration test class which use docker for real cassandra database
public abstract class AbstractTest {
public static final String CASSANDRA_KEYSPACE = "user_group";
public static final String CASSANDRA_SCHEMA_SCRIPT = "cassandra/schema.cql";
public static final String CASSANDRA_IMAGE = "cassandra:3.11.2";
public static final int CASSANDRA_PORT = 9042;
private static final Logger log = LoggerFactory.getLogger(AbstractTest.class);
protected static final CassandraContainer CASSANDRA = new CassandraContainer(CASSANDRA_IMAGE);
static {
startCassandra();
}
protected static void startCassandra() {
CASSANDRA.withInitScript(CASSANDRA_SCHEMA_SCRIPT)
.withExposedPorts(CASSANDRA_PORT)
.withStartupTimeout(Duration.ofMinutes(5))
.withReuse(true)
.start();
System.setProperty("spring.data.cassandra.keyspace-name", CASSANDRA_KEYSPACE);
System.setProperty("spring.data.cassandra.contact-points", "localhost:" + CASSANDRA.getMappedPort(9042));
System.setProperty("spring.data.cassandra.local-datacenter", "datacenter1");
System.setProperty("spring.data.cassandra.schema-action", "create_if_not_exists");
}
public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
// Cassandra
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(
applicationContext,
"spring.data.cassandra.keyspace-name=" + CASSANDRA_KEYSPACE,
"spring.data.cassandra.contact-points=" + "localhost:" + CASSANDRA.getMappedPort(CASSANDRA_PORT),
"spring.data.cassandra.local-datacenter=" + "datacenter1",
"spring.data.cassandra.schema-action=" + "create_if_not_exists"
);
Runtime.getRuntime().addShutdownHook(new Thread(CASSANDRA::stop));
}
}
protected static Session getCassandraSession() {
return CASSANDRA.getCluster().connect(CASSANDRA_KEYSPACE);
}
}
My integration test
@ActiveProfiles("integration")
@AutoConfigureWebTestClient
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureDataCassandra
@ContextConfiguration(initializers = AbstractTest.Initializer.class)
@EnableCassandraRepositories(basePackageClasses = {UserGroupRepository.class})
public class UserGroupControllerTest extends AbstractTest {
private static final Logger log = LoggerFactory.getLogger(UserGroupControllerTest.class);
@Autowired
private WebTestClient webTestClient;
@Autowired
private UserGroupRepository userGroupRepository;
@Test
void test_cassandra_upAndRunning() {
assertThat(CASSANDRA.isRunning()).isTrue();
Session session = getCassandraSession();
ResultSet result = session.execute("select * from user_group where group_id='group001'");
Row row = result.iterator().next();
assertEquals("User group 1", row.getString("group_name"));
}
@Test
public void test_getCurrentUserGroup_success() {
log.info("Instance of userGroupRepository {}", userGroupRepository.getClass().getName());
UserGroupDto userGroupDto = webTestClient.get()
.uri("/api/v1/usergroups")
.header(HttpHeaders.AUTHORIZATION, "Bearer abc")
.exchange()
.expectStatus()
.isOk()
.expectBody(UserGroupDto.class)
.returnResult()
.getResponseBody();
Assertions.assertNotNull(userGroupDto);
}
}
The injection code
@Autowired
private UserGroupRepository userGroupRepository;
Spring always inject Mockito bean for this repository, althought I try to use @EnableCassandraRepositories and @AutoConfigureDataCassandra but it seems not work.
My question is how to force Spring to inject the real implementation of my cassandra repository? Thanks.