Skip to content

Commit 313b2be

Browse files
committed
Polish "Add test slice for Spring Data Cassandra"
See gh-17490
1 parent ae152b1 commit 313b2be

File tree

22 files changed

+174
-162
lines changed

22 files changed

+174
-162
lines changed

spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6947,6 +6947,34 @@ TIP: Sometimes writing Spring WebFlux tests is not enough; Spring Boot can help
69476947

69486948

69496949

6950+
[[boot-features-testing-spring-boot-applications-testing-autoconfigured-cassandra-test]]
6951+
==== Auto-configured Data Cassandra Tests
6952+
You can use `@DataCassandraTest` to test Cassandra applications.
6953+
By default, it configures a `CassandraTemplate`, scans for `@Table` classes, and configures Spring Data Cassandra repositories.
6954+
Regular `@Component` beans are not loaded into the `ApplicationContext`.
6955+
(For more about using Cassandra with Spring Boot, see "<<boot-features-cassandra>>", earlier in this chapter.)
6956+
6957+
TIP: A list of the auto-configuration settings that are enabled by `@DataCassandraTest` can be <<appendix-test-auto-configuration.adoc#test-auto-configuration,found in the appendix>>.
6958+
6959+
The following example shows a typical setup for using Cassandra tests in Spring Boot:
6960+
6961+
[source,java,indent=0]
6962+
----
6963+
import org.springframework.beans.factory.annotation.Autowired;
6964+
import org.springframework.boot.test.autoconfigure.data.cassandra.DataCassandraTest;
6965+
6966+
@DataCassandraTest
6967+
class ExampleDataCassandraTests {
6968+
6969+
@Autowired
6970+
private YourRepository repository;
6971+
6972+
//
6973+
}
6974+
----
6975+
6976+
6977+
69506978
[[boot-features-testing-spring-boot-applications-testing-autoconfigured-jpa-test]]
69516979
==== Auto-configured Data JPA Tests
69526980
You can use the `@DataJpaTest` annotation to test JPA applications.

spring-boot-project/spring-boot-test-autoconfigure/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ dependencies {
3030
optional("org.springframework:spring-web")
3131
optional("org.springframework:spring-webmvc")
3232
optional("org.springframework:spring-webflux")
33+
optional("org.springframework.data:spring-data-cassandra")
3334
optional("org.springframework.data:spring-data-jdbc")
3435
optional("org.springframework.data:spring-data-jpa")
3536
optional("org.springframework.data:spring-data-ldap")
@@ -78,6 +79,7 @@ dependencies {
7879
testImplementation("org.skyscreamer:jsonassert")
7980
testImplementation("org.springframework.hateoas:spring-hateoas")
8081
testImplementation("org.springframework.plugin:spring-plugin-core")
82+
testImplementation("org.testcontainers:cassandra")
8183
testImplementation("org.testcontainers:junit-jupiter")
8284
testImplementation("org.testcontainers:neo4j")
8385
testImplementation("org.testcontainers:testcontainers")

spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/cassandra/AutoConfigureDataCassandra.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -27,11 +27,11 @@
2727

2828
/**
2929
* {@link ImportAutoConfiguration Auto-configuration imports} for typical Data Cassandra
30-
* tests. Most tests should consider using {@link DataCassandraTest} rather than using
31-
* this annotation directly.
30+
* tests. Most tests should consider using {@link DataCassandraTest @DataCassandraTest}
31+
* rather than using this annotation directly.
3232
*
3333
* @author Artsiom Yudovin
34-
* @since 2.1.0
34+
* @since 2.4.0
3535
* @see DataCassandraTest
3636
*/
3737
@Target(ElementType.TYPE)

spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/cassandra/DataCassandraTest.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -30,25 +30,25 @@
3030
import org.springframework.boot.test.autoconfigure.OverrideAutoConfiguration;
3131
import org.springframework.boot.test.autoconfigure.core.AutoConfigureCache;
3232
import org.springframework.boot.test.autoconfigure.filter.TypeExcludeFilters;
33-
import org.springframework.context.annotation.ComponentScan;
33+
import org.springframework.context.annotation.ComponentScan.Filter;
3434
import org.springframework.core.annotation.AliasFor;
3535
import org.springframework.core.env.Environment;
3636
import org.springframework.test.context.BootstrapWith;
3737
import org.springframework.test.context.junit.jupiter.SpringExtension;
3838

3939
/**
40-
* Annotation that can be used in combination with {@code @RunWith(SpringRunner.class)}
41-
* for a typical Cassandra test. Can be used when a test focuses <strong>only</strong> on
40+
* Annotation that can be used for a Cassandra test that focuses <strong>only</strong> on
4241
* Cassandra components.
4342
* <p>
4443
* Using this annotation will disable full auto-configuration and instead apply only
4544
* configuration relevant to Cassandra tests.
4645
* <p>
47-
* By default, tests annotated with {@code @DataCassandraTest} will use an embedded
48-
* in-memory Cassandra process (if available).
46+
* When using JUnit 4, this annotation should be used in combination with
47+
* {@code @RunWith(SpringRunner.class)}.
4948
*
5049
* @author Artsiom Yudovin
51-
* @since 2.1.0
50+
* @author Stephane Nicoll
51+
* @since 2.4.0
5252
*/
5353
@Target(ElementType.TYPE)
5454
@Retention(RetentionPolicy.RUNTIME)
@@ -86,14 +86,14 @@
8686
* application context.
8787
* @return include filters to apply
8888
*/
89-
ComponentScan.Filter[] includeFilters() default {};
89+
Filter[] includeFilters() default {};
9090

9191
/**
9292
* A set of exclude filters which can be used to filter beans that would otherwise be
9393
* added to the application context.
9494
* @return exclude filters to apply
9595
*/
96-
ComponentScan.Filter[] excludeFilters() default {};
96+
Filter[] excludeFilters() default {};
9797

9898
/**
9999
* Auto-configuration exclusions that should be applied for this test.

spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/cassandra/DataCassandraTestContextBootstrapper.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,21 +18,21 @@
1818

1919
import org.springframework.boot.test.context.SpringBootTestContextBootstrapper;
2020
import org.springframework.core.annotation.MergedAnnotations;
21+
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
2122
import org.springframework.test.context.TestContextBootstrapper;
2223

2324
/**
2425
* {@link TestContextBootstrapper} for {@link DataCassandraTest @DataCassandraTest}
2526
* support.
2627
*
2728
* @author Artsiom Yudovin
28-
* @since 2.1.0
2929
*/
30-
public class DataCassandraTestContextBootstrapper extends SpringBootTestContextBootstrapper {
30+
class DataCassandraTestContextBootstrapper extends SpringBootTestContextBootstrapper {
3131

3232
@Override
3333
protected String[] getProperties(Class<?> testClass) {
34-
return MergedAnnotations.from(testClass, MergedAnnotations.SearchStrategy.INHERITED_ANNOTATIONS)
35-
.get(DataCassandraTest.class).getValue("properties", String[].class).orElse(null);
34+
return MergedAnnotations.from(testClass, SearchStrategy.INHERITED_ANNOTATIONS).get(DataCassandraTest.class)
35+
.getValue("properties", String[].class).orElse(null);
3636
}
3737

3838
}

spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/data/cassandra/DataCassandraTypeExcludeFilter.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -23,9 +23,8 @@
2323
* {@link TypeExcludeFilter} for {@link DataCassandraTest @DataCassandraTest}.
2424
*
2525
* @author Artsiom Yudovin
26-
* @since 2.1.0
2726
*/
28-
public class DataCassandraTypeExcludeFilter extends StandardAnnotationCustomizableTypeExcludeFilter<DataCassandraTest> {
27+
class DataCassandraTypeExcludeFilter extends StandardAnnotationCustomizableTypeExcludeFilter<DataCassandraTest> {
2928

3029
protected DataCassandraTypeExcludeFilter(Class<?> testClass) {
3130
super(testClass);

spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration
66
org.springframework.boot.test.autoconfigure.data.cassandra.AutoConfigureDataCassandra=\
77
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
88
org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,\
9+
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\
10+
org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\
911
org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration
1012

1113
# AutoConfigureDataJdbc auto-configuration imports

spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/actuate/metrics/AutoConfigureMetricsSpringBootApplication.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.springframework.boot.SpringBootConfiguration;
2020
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
2121
import org.springframework.boot.autoconfigure.SpringBootApplication;
22+
import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration;
2223

2324
/**
2425
* Example {@link SpringBootApplication @SpringBootApplication} for use with
@@ -27,7 +28,7 @@
2728
* @author Chris Bono
2829
*/
2930
@SpringBootConfiguration
30-
@EnableAutoConfiguration
31+
@EnableAutoConfiguration(exclude = CassandraAutoConfiguration.class)
3132
class AutoConfigureMetricsSpringBootApplication {
3233

3334
}

spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/cassandra/DataCassandraTestIntegrationTests.java

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,23 +16,25 @@
1616

1717
package org.springframework.boot.test.autoconfigure.data.cassandra;
1818

19+
import java.time.Duration;
1920
import java.util.UUID;
2021

21-
import com.datastax.driver.core.Cluster;
22+
import com.datastax.oss.driver.api.core.CqlSession;
23+
import com.datastax.oss.driver.api.core.CqlSessionBuilder;
2224
import org.junit.jupiter.api.Test;
25+
import org.testcontainers.containers.CassandraContainer;
2326
import org.testcontainers.junit.jupiter.Container;
27+
import org.testcontainers.junit.jupiter.Testcontainers;
2428

2529
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
2630
import org.springframework.beans.factory.annotation.Autowired;
2731
import org.springframework.boot.test.autoconfigure.data.redis.ExampleService;
28-
import org.springframework.boot.test.util.TestPropertyValues;
29-
import org.springframework.boot.testsupport.testcontainers.CassandraContainer;
30-
import org.springframework.boot.testsupport.testcontainers.DisabledWithoutDockerTestcontainers;
32+
import org.springframework.boot.test.context.TestConfiguration;
3133
import org.springframework.context.ApplicationContext;
32-
import org.springframework.context.ApplicationContextInitializer;
33-
import org.springframework.context.ConfigurableApplicationContext;
34+
import org.springframework.context.annotation.Bean;
3435
import org.springframework.data.cassandra.core.CassandraTemplate;
35-
import org.springframework.test.context.ContextConfiguration;
36+
import org.springframework.test.context.DynamicPropertyRegistry;
37+
import org.springframework.test.context.DynamicPropertySource;
3638

3739
import static org.assertj.core.api.Assertions.assertThat;
3840
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@@ -42,13 +44,21 @@
4244
*
4345
* @author Artsiom Yudovin
4446
*/
45-
@DisabledWithoutDockerTestcontainers
46-
@ContextConfiguration(initializers = DataCassandraTestIntegrationTests.Initializer.class)
47-
@DataCassandraTest
47+
@DataCassandraTest(properties = { "spring.data.cassandra.local-datacenter=datacenter1",
48+
"spring.data.cassandra.schema-action=create-if-not-exists",
49+
"spring.data.cassandra.connection.connect-timeout=10s", "spring.data.cassandra.request.timeout=5s" })
50+
@Testcontainers(disabledWithoutDocker = true)
4851
class DataCassandraTestIntegrationTests {
4952

5053
@Container
51-
public static CassandraContainer cassandra = new CassandraContainer();
54+
static final CassandraContainer<?> cassandra = new CassandraContainer<>().withStartupAttempts(5)
55+
.withStartupTimeout(Duration.ofMinutes(10));
56+
57+
@DynamicPropertySource
58+
static void cassandraProperties(DynamicPropertyRegistry registry) {
59+
registry.add("spring.data.cassandra.contact-points",
60+
() -> cassandra.getHost() + ":" + cassandra.getFirstMappedPort());
61+
}
5262

5363
@Autowired
5464
private CassandraTemplate cassandraTemplate;
@@ -67,36 +77,28 @@ void didNotInjectExampleService() {
6777

6878
@Test
6979
void testRepository() {
70-
71-
Person person = new Person();
72-
person.setDescription("Look, new @DataCassandraTest!");
80+
ExampleEntity entity = new ExampleEntity();
81+
entity.setDescription("Look, new @DataCassandraTest!");
7382
String id = UUID.randomUUID().toString();
74-
person.setId(id);
75-
76-
Person savedEntity = this.exampleRepository.save(person);
77-
Person getEntity = this.cassandraTemplate.selectOneById(id, Person.class);
78-
83+
entity.setId(id);
84+
ExampleEntity savedEntity = this.exampleRepository.save(entity);
85+
ExampleEntity getEntity = this.cassandraTemplate.selectOneById(id, ExampleEntity.class);
7986
assertThat(getEntity).isNotNull();
8087
assertThat(getEntity.getId()).isNotNull();
8188
assertThat(getEntity.getId()).isEqualTo(savedEntity.getId());
82-
8389
this.exampleRepository.deleteAll();
8490
}
8591

86-
static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
87-
88-
@Override
89-
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
90-
TestPropertyValues.of("spring.data.cassandra.port=" + cassandra.getFirstMappedPort())
91-
.and("spring.data.cassandra.keyspaceName=test")
92-
.and("spring.data.cassandra.schema-action=CREATE_IF_NOT_EXISTS")
93-
.applyTo(configurableApplicationContext.getEnvironment());
92+
@TestConfiguration(proxyBeanMethods = false)
93+
static class KeyspaceTestConfiguration {
9494

95-
Cluster cluster = Cluster.builder().withoutJMXReporting()
96-
.addContactPoints(cassandra.getContainerIpAddress()).withPort(cassandra.getFirstMappedPort())
97-
.build();
98-
cluster.connect().execute("CREATE KEYSPACE test "
99-
+ "WITH replication = {'class':'SimpleStrategy', 'replication_factor' : 1};");
95+
@Bean
96+
CqlSession cqlSession(CqlSessionBuilder cqlSessionBuilder) {
97+
try (CqlSession session = cqlSessionBuilder.build()) {
98+
session.execute("CREATE KEYSPACE IF NOT EXISTS boot_test"
99+
+ " WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };");
100+
}
101+
return cqlSessionBuilder.withKeyspace("boot_test").build();
100102
}
101103

102104
}

spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/cassandra/DataCassandraTestPropertiesIntegrationTests.java

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,34 +16,29 @@
1616

1717
package org.springframework.boot.test.autoconfigure.data.cassandra;
1818

19+
import com.datastax.oss.driver.api.core.CqlSession;
20+
import com.datastax.oss.driver.api.core.context.DriverContext;
21+
import com.datastax.oss.driver.api.core.type.codec.registry.CodecRegistry;
1922
import org.junit.jupiter.api.Test;
20-
import org.testcontainers.junit.jupiter.Container;
2123

2224
import org.springframework.beans.factory.annotation.Autowired;
23-
import org.springframework.boot.test.util.TestPropertyValues;
24-
import org.springframework.boot.testsupport.testcontainers.CassandraContainer;
25-
import org.springframework.boot.testsupport.testcontainers.DisabledWithoutDockerTestcontainers;
26-
import org.springframework.context.ApplicationContextInitializer;
27-
import org.springframework.context.ConfigurableApplicationContext;
25+
import org.springframework.boot.test.context.TestConfiguration;
26+
import org.springframework.context.annotation.Bean;
2827
import org.springframework.core.env.Environment;
29-
import org.springframework.test.context.ContextConfiguration;
3028

3129
import static org.assertj.core.api.Assertions.assertThat;
30+
import static org.mockito.BDDMockito.given;
31+
import static org.mockito.Mockito.mock;
3232

3333
/**
3434
* Tests for the {@link DataCassandraTest#properties properties} attribute of
3535
* {@link DataCassandraTest @DataCassandraTest}.
3636
*
3737
* @author Artsiom Yudovin
3838
*/
39-
@DisabledWithoutDockerTestcontainers
40-
@ContextConfiguration(initializers = DataCassandraTestPropertiesIntegrationTests.Initializer.class)
4139
@DataCassandraTest(properties = "spring.profiles.active=test")
4240
class DataCassandraTestPropertiesIntegrationTests {
4341

44-
@Container
45-
public static final CassandraContainer cassandra = new CassandraContainer();
46-
4742
@Autowired
4843
private Environment environment;
4944

@@ -52,12 +47,17 @@ void environmentWithNewProfile() {
5247
assertThat(this.environment.getActiveProfiles()).containsExactly("test");
5348
}
5449

55-
static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
50+
@TestConfiguration(proxyBeanMethods = false)
51+
static class CassandraMockConfiguration {
5652

57-
@Override
58-
public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
59-
TestPropertyValues.of("spring.data.cassandra.port=" + cassandra.getFirstMappedPort())
60-
.applyTo(configurableApplicationContext.getEnvironment());
53+
@Bean
54+
CqlSession cqlSession() {
55+
DriverContext context = mock(DriverContext.class);
56+
CodecRegistry codecRegistry = mock(CodecRegistry.class);
57+
given(context.getCodecRegistry()).willReturn(codecRegistry);
58+
CqlSession cqlSession = mock(CqlSession.class);
59+
given(cqlSession.getContext()).willReturn(context);
60+
return cqlSession;
6161
}
6262

6363
}

0 commit comments

Comments
 (0)