Reputation: 983
I run my Integration Test cases with Spring Boot with the help of my local Redis server on my machine.
But I want an embedded Redis server which is not dependent on any server and can run on any environment, like the H2 in-memory database. How can I do it?
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@IntegrationTest("server.port:0")
@SpringApplicationConfiguration(classes = Application.class)
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
public class MasterIntegrationTest {
}
Upvotes: 40
Views: 85480
Reputation: 4689
edit : I would now strongly suggest to go the testcontainers route as explained in @magiccrafter answer, I am also using it for my tests now.
You can use ozimov/embedded-redis as a Maven(-test)-dependency (this is the successor of kstyrc/embedded-redis).
Add the dependency to your pom.xml
<dependencies>
...
<dependency>
<groupId>it.ozimov</groupId>
<artifactId>embedded-redis</artifactId>
<version>0.7.1</version>
<scope>test</scope>
</dependency>
Adjust your application properties for your integration test
spring.redis.host=localhost
spring.redis.port=6379
Use the embedded redis server in a test configuration
@TestConfiguration
public static class EmbededRedisTestConfiguration {
private final redis.embedded.RedisServer redisServer;
public EmbededRedisTestConfiguration(@Value("${spring.redis.port}") final int redisPort) throws IOException {
this.redisServer = new redis.embedded.RedisServer(redisPort);
}
@PostConstruct
public void startRedis() {
this.redisServer.start();
}
@PreDestroy
public void stopRedis() {
this.redisServer.stop();
}
}
Upvotes: 28
Reputation: 7069
If your are using spring and reactive to access data with redis reactively.
Meaning you're having a ReactiveRedisConnectionFactory
(with a RedisConnectionFactory
bean) and a LettuceConnectionFactory
then you may want to follow this approach to set an embedded redis for multiple test classes.
First add the playtika embedded redis to your dependencies:
dependencies {
testCompile("com.playtika.testcontainers:embedded-redis:2.0.9")
}
Then set the redis host and port as the embedded.redis
one in your application.yml (that are generated by the embedded redis as env variable on creation).
spring:
redis:
host: \${embedded.redis.host:localhost}
port: \${embedded.redis.port:6739}
In a bootstrap-redisnoauth.properties
file, set the env variable embedded.redis.requirepass=false
so that it does not require password.
Then in your test use the active profile:
@ActiveProfiles("redisnoauth")
And make sure to have this @TestConfiguration
in your test class as well so that will connect you to the redis spawned on a randomly generated port.
@Category(IntegrationTest.class)
@RunWith(SpringRunner.class)
@SpringBootTest
@ActiveProfiles("redisnoauth")
public class RedisCacheTest {
@TestConfiguration
static class RedisTestConfiguration {
@Bean
public RedisConnectionFactory redisConnectionFactory(@Value("${spring.redis.host}") String host,
@Value("${spring.redis.port}") int port) {
return new LettuceConnectionFactory(host, port);
}
@Bean
public RedisOperations<String, String> stringKeyAndStringValueRedisOperations(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer(UTF_8));
redisTemplate.setValueSerializer(new StringRedisSerializer(UTF_8));
return redisTemplate;
}
}
@Test
public void myTest() {
// your test
}
}
And it should work smoothly.
Upvotes: 1
Reputation: 5484
Another neat way is to use the testcontainers library which can run any type of application that can in a Docker container and Redis is no exception. What I like best is that it is lightly coupled with the Spring Test ecosystem.
maven's dependency:
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>${testcontainers.version}</version>
</dependency>
simple integration test:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = {"management.port=0"})
@ContextConfiguration(initializers = AbstractIntegrationTest.Initializer.class)
@DirtiesContext
public abstract class AbstractIntegrationTest {
private static int REDIS_PORT = 6379;
@ClassRule
public static GenericContainer redis = new GenericContainer("redis:5-alpine").withExposedPorts(REDIS_PORT);
public static class Initializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext ctx) {
// Spring Boot 1.5.x
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(ctx,
"spring.redis.host=" + redis.getContainerIpAddress(),
"spring.redis.port=" + redis.getMappedPort(REDIS_PORT));
// Spring Boot 2.x.
TestPropertyValues.of(
"spring.redis.host:" + redis.getContainerIpAddress(),
"spring.redis.port:" + redis.getMappedPort(REDIS_PORT))
.applyTo(ctx);
}
}
}
Since Spring Framework 5.2.5 (Spring Boot 2.3.x) you can use the powerful DynamicPropertySource
annotation.
Here is an example:
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
public abstract class AbstractIT {
static GenericContainer redisContainer = new GenericContainer("redis:5-alpine").withExposedPorts(6379);
@DynamicPropertySource
static void properties(DynamicPropertyRegistry r) throws IOException {
r.add("spring.redis.host", redisContainer::getContainerIpAddress);
r.add("spring.redis.port", redisContainer::getFirstMappedPort);
}
}
Upvotes: 14
Reputation: 109
you can see this repository: https://github.com/caryyu/spring-embedded-redis-server , fully integrated with Spring and Spring Boot
<dependency>
<groupId>com.github.caryyu</groupId>
<artifactId>spring-embedded-redis-server</artifactId>
<version>1.1</version>
</dependency>
@Bean
public RedisServerConfiguration redisServerConfiguration() {
return new RedisServerConfiguration();
}
spring:
redis:
port: 6379
embedded: true
Upvotes: 1
Reputation: 6452
You can use an embedded Redis like https://github.com/kstyrc/embedded-redis
Adjust the properties for your integration test to point to your embedded redis, for example :
spring:
redis:
host: localhost
port: 6379
Instanciate the embedded redis server in a component that is defined in your tests only :
@Component
public class EmbededRedis {
@Value("${spring.redis.port}")
private int redisPort;
private RedisServer redisServer;
@PostConstruct
public void startRedis() throws IOException {
redisServer = new RedisServer(redisPort);
redisServer.start();
}
@PreDestroy
public void stopRedis() {
redisServer.stop();
}
}
Upvotes: 50