embedded-redis:Redis embedded server for Java integration testing
redis-unit:Redis instance for unit testing applications.
原理:
启动java的嵌入式redis,然后获取启动时的随机端口,通过spring-redis的创建工厂映射自己需要的bean(使用雪球RedisCluster4的,redis-sdk里面有单元测试:http://git.snowballfinance.com/lib/redis-cluster4)
RedisCluster4使用步骤:
test-tools项目已经封装了对redis cluster 4的依赖和默认设置,故只需引入pom即可
<dependency>
<groupId>com.xueqiu.infra</groupId>
<artifactId>test-tools</artifactId>
<version>1.0.3</version>
</dependency> |
version版本根据实时情况更新
redis cluster 4使用示例:
只需指定你要启动的节点数(示例中启动了三个节点),详情见如下示例地址
示例地址:
源码版:http://git.snowballfinance.com/lib/test-tools
/**
* RedisCluster 4 unit test
*
* redis 4.X集群的单元测试,同时是为了兼容雪球的redis SDK(RedisCluster至于名字是历史问题向下兼容造成的)
*/
@Test
public void testRedisCluster4(){
TestEnvironment env = new TestEnvironmentBuilder()
.withRedisCluster4(3) .build();
try {
RedisCluster4 redisCluster4 = env.redisCluster4().get();
List<RedisClusterConfig> clusterConfigs = redisCluster4.getRedisClusterConfigList();
System.out.println(clusterConfigs);
String connectString = redisCluster4.getConnectionStringList().stream().collect(Collectors.joining(","));
com.xueqiu.infra.redis4.RedisCluster redisClient = RedisClusterImpl.create(connectString, 4, MetricsFactory.create("RedisClusterImplUnitTest"));
redisClient.set("k1", "v1");
System.out.println(redisClient.get("k1"));
Assert.assertEquals("v1", redisClient.get("k1"));
} catch (Exception e) {
Assert.assertTrue(false);
throw new RuntimeException("redis cluster 4 test error.", e);
}
} |
示例地址:
spring版:http://git.snowballfinance.com/hekuangsheng/xueqiu-push
test的resource目录下添加sql文件
src
--main
--test
--java
--包路径
--TestConfig.java
--BaseTests.java
--limit --RateLimitClientTest.java |
BaseTestConfig.java
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xueqiu.infra.test.tools.TestEnvironment;
import com.xueqiu.infra.test.tools.TestEnvironmentBuilder;
import com.xueqiu.infra.test.tools.entity.RedisCluster4;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.util.Arrays;
import java.util.List;
@Configuration
@AutoConfigureOrder(0)
public class BaseTestConfig {
private TestEnvironment env = new TestEnvironmentBuilder()
.withH2Database(Arrays.asList("sql/demo_schema.sql", "sql/demo_data.sql"))
.withRedisCluster4(4)
.build();
@Bean
public DataSource dataSource() {
return TestEnvironment.jdbcDataSource()
.orElseThrow(() -> new RuntimeException("init test data source fail"));
}
@Bean(name = "xueqiupushTemplate")
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource());
}
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
DataSourceTransactionManager tm = new DataSourceTransactionManager();
tm.setDataSource(dataSource);
return tm;
}
@Bean
public RedisConnectionFactory factory(){
RedisCluster4 redisCluster4 = TestEnvironment.redisCluster4()
.orElseThrow(() -> new RuntimeException("init test redis cluster fail"));
List<String> connectionStringList = redisCluster4.getConnectionStringList();
RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(connectionStringList);
RedisConnectionFactory connectionFactory = new LettuceConnectionFactory(redisClusterConfiguration);
return connectionFactory;
}
@Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
StringRedisTemplate template = new StringRedisTemplate(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
@Bean("rateLimitLua")
public DefaultRedisScript getRedisScript() {
DefaultRedisScript redisScript = new DefaultRedisScript();
redisScript.setLocation(new ClassPathResource("limit/ratelimit.lua"));
redisScript.setResultType(java.util.List.class);
return redisScript;
}
@Bean("rateLimitInitLua")
public DefaultRedisScript getInitRedisScript() {
DefaultRedisScript redisScript = new DefaultRedisScript();
redisScript.setLocation(new ClassPathResource("limit/ratelimitInit.lua"));
redisScript.setResultType(Long.class);
return redisScript;
}
} |
BaseJunit4Test.java
import org.junit.Ignore;
import org.junit.runner.RunWith;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Controller;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
import org.springframework.transaction.annotation.Transactional;
@Ignore
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = BaseTestConfig.class)
@TestExecutionListeners(TransactionalTestExecutionListener.class)
@Transactional
@ComponentScan(
basePackages = {
"com.xueqiu.infra.push.server.entity",
"com.xueqiu.infra.push.server.limit",
},
excludeFilters = {
@ComponentScan.Filter(Controller.class)
}
)
public class BaseJunit4Test extends AbstractJUnit4SpringContextTests {
} |
RateLimitClientTest.java
import com.xueqiu.infra.push.server.BaseJunit4Test;
import org.junit.Test;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.RedisScript;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class RateLimitClientTest extends BaseJunit4Test {
private static final String UNIT_TEST_KEY = "UNIT_TEST_KEY";
private final static long PERMITS_PER_SECOND = 3250;
@Resource
private StringRedisTemplate stringRedisTemplate;
@Resource(name = "rateLimitLua")
private RedisScript<List> rateLimitLua;
@Resource(name = "rateLimitInitLua")
private RedisScript<Long> rateLimitInitLua;
RateLimitClient rateLimitClient = new RateLimitClient();
@Test
public void initToken_and_acquireIntervalAndToken_test() {
Long acquire = stringRedisTemplate.execute(rateLimitInitLua,
Collections.singletonList(rateLimitClient.getKey(UNIT_TEST_KEY)), String.valueOf(PERMITS_PER_SECOND), String.valueOf(PERMITS_PER_SECOND));
assertEquals(Long.valueOf(1L), acquire);
boolean result = stringRedisTemplate.hasKey(rateLimitClient.getKey(UNIT_TEST_KEY));
assertTrue(result);
List<Object> objectList = stringRedisTemplate.opsForHash().values(rateLimitClient.getKey(UNIT_TEST_KEY));
assertEquals(3, objectList.size());
}
} |