Inject implementation of CassandraRepository in Spring Boot test

1.1k Views Asked by At

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.

enter image description here

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.

1

There are 1 best solutions below

0
On

The root cause is invalid usage of ActiveProfile and Profile in Spring. Update TestConfig to use @Profile instead of @ActiveProfiles.