在 junit 测试中禁用 RedisHttpSessionConfiguration
Posted
技术标签:
【中文标题】在 junit 测试中禁用 RedisHttpSessionConfiguration【英文标题】:Disabling RedisHttpSessionConfiguration in junit tests 【发布时间】:2016-04-17 03:42:46 【问题描述】:我正在使用spring-boot
和spring-session
构建一个简单的rest api。生产应用应该使用 redis-session 实现,而测试应该使用默认的(非 redis)spring-session。
但是,当在项目中声明 spring-boot-starter-redis
maven 依赖项时,spring-boot 将自动创建一个 org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration
,而 @EnableRedisHttpSession
注释不会出现在测试配置中的任何位置。
我的设置
应用代码:
// base session config for both prod/dev and test/ci
public class BaseSessionConfig
@Bean
public HeaderHttpSessionStrategy sessionStrategy()
return new HeaderHttpSessionStrategy();
// enable the redis session only in these profiles
@Configuration
@EnableRedisHttpSession
@Profile("prod", "dev", "local", "vagrant")
public class RedisSessionConfig extends BaseSessionConfig
测试:
@WebIntegrationTest
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MyApplication.class, MyTestApplicationConfig.class)
public class AuthenticationResourceTest
private RestTemplate restTemplate = new TestRestTemplate();
@Test
public void testUnauthenticated()
HttpHeaders headers = restTemplate.getForEntity("http://localhost:8080/api/session", String.class).getHeaders();
// ...
// session configuration for the test environments
// no redis enabled
@Configuration
@Profile("ci", "test")
public class MyTestApplicationConfig extends BaseSessionConfig
如何在 junit 测试中禁用 redis 会话自动配置?
测试期间的堆栈跟踪:
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:117)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:228)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:230)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:289)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:291)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:249)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:193)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:119)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'enableRedisKeyspaceNotificationsInitializer' defined in class path resource [org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfiguration.class]: Invocation of init method failed; nested exception is org.springframework.data.redis.RedisConnectionFailureException: Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1578)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:545)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:764)
at org.springframework.boot.SpringApplication.doRun(SpringApplication.java:357)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:305)
at org.springframework.boot.test.SpringApplicationContextLoader.loadContext(SpringApplicationContextLoader.java:98)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)
... 24 more
Caused by: org.springframework.data.redis.RedisConnectionFailureException: Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.fetchJedisConnector(JedisConnectionFactory.java:162)
at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.getConnection(JedisConnectionFactory.java:251)
at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.getConnection(JedisConnectionFactory.java:58)
at org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration$EnableRedisKeyspaceNotificationsInitializer.afterPropertiesSet(RedisHttpSessionConfiguration.java:166)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1637)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)
... 40 more
Caused by: redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
at redis.clients.util.Pool.getResource(Pool.java:50)
at redis.clients.jedis.JedisPool.getResource(JedisPool.java:99)
at redis.clients.jedis.JedisPool.getResource(JedisPool.java:12)
at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.fetchJedisConnector(JedisConnectionFactory.java:155)
... 45 more
Caused by: redis.clients.jedis.exceptions.JedisConnectionException: java.net.ConnectException: Connection refused
at redis.clients.jedis.Connection.connect(Connection.java:164)
at redis.clients.jedis.BinaryClient.connect(BinaryClient.java:82)
at redis.clients.jedis.BinaryJedis.connect(BinaryJedis.java:1641)
at redis.clients.jedis.JedisFactory.makeObject(JedisFactory.java:85)
at org.apache.commons.pool2.impl.GenericObjectPool.create(GenericObjectPool.java:868)
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:435)
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:363)
at redis.clients.util.Pool.getResource(Pool.java:48)
... 48 more
Caused by: java.net.ConnectException: Connection refused
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at redis.clients.jedis.Connection.connect(Connection.java:158)
... 55 more
编辑
我想通了。尽管配置上没有 EnableRedisSession
注释,但 RedisHttpSessionConfig
在测试中加载的原因是 spring-boot-starter-web 附带的自动配置:SessionAutoConfiguration
所以在测试中,这是需要从自动配置中排除的类:
@WebIntegrationTest
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = TestAppConfig.class)
public class AuthenticationResourceTest
private RestTemplate restTemplate = new TestRestTemplate();
@Test
public void testUnauthenticated()
HttpHeaders headers = restTemplate.getForEntity("http://localhost:8080/api/session", String.class).getHeaders();
@Configuration
@SpringBootApplication(exclude = SessionAutoConfiguration.class, SessionRedisHttpConfiguration.class)
public class TestAppConfig
@Configuration
static class SessionConfig extends BaseSessionConfig
【问题讨论】:
尝试使用 @SpringBootApplication 注释 MyTestApplicationConfig 并执行此操作 @SpringBootApplication(exclude = RedisHttpSessionConfiguration.class) 【参考方案1】:使用@ActiveProfiles
testing 注释启用某些配置文件进行测试。如果您不激活在 RedisSessionConfig
上定义的配置文件,则不应加载该配置。
但还要确保 RedisHttpSessionConfiguration
不是通过自动配置加载的。
评论反应:
我不确定 Redis 是否有它的自动配置类。 Looking into Spring Boot,它有。所以你需要在测试时排除它。 Look into this SO thread how to do it.
【讨论】:
不幸的是,这不起作用。我已经尝试过类似的建议,就像这里提到的那样:***.com/questions/26698071/… - 但RedisHttpSessionConfiguration
仍然加载到测试中(也启用了@ActiveProfiles("test")
。据我了解spring-boot autoconfig,需要有一个@ 987654331@ 包含自动配置类的文件 + 配置上的一些 @Conditional
注释。但是,此配置没有:git.io/vzO1C以上是关于在 junit 测试中禁用 RedisHttpSessionConfiguration的主要内容,如果未能解决你的问题,请参考以下文章
在不创建上下文的情况下禁用 Spring 和 Junit5 测试