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.
The root cause is invalid usage of ActiveProfile and Profile in Spring. Update TestConfig to use @Profile instead of @ActiveProfiles.