Spring测试:在同一虚拟机中已经存在一个相同名称为“myCacheManager”的另一个CacheManager。

9

在您将此标记为重复之前,请先阅读问题。我已经阅读了所有关于此异常的内容,但它并没有解决我的问题。而且我确实遇到了稍微不同的异常,例如 Another CacheManager with same name 'myCacheManager' already exists 而不是 Another unnamed CacheManager already exists

Spring配置:

<cache:annotation-driven cache-manager="cacheManager"/>

<bean id="cacheManager"
      class="org.springframework.cache.ehcache.EhCacheCacheManager"
      p:cacheManager-ref="ehcache"/>
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
      p:configLocation="ehcache.xml"
      p:cacheManagerName="myCacheManager"
      p:shared="true"/>

ehcache

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
        updateCheck="false" name="myCacheManager">

</ehcache>

问题在于我有1个(未来可能更多)测试类用于测试安全性,这些类还会加载SecurityContext.xml文件。
因此,大多数测试类都具有以下注释:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:ApplicationContext.xml")

然而,导致问题的类是:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
    "classpath:ApplicationContext.xml",
    "classpath:SecurityContext.xml"
})

看起来由于位置不同,上下文被重新加载,但是ehcacheManager仍然处于之前测试的活动状态。

注意:只有在运行多个测试(例如像清理+构建)时才会出现这种情况。单独运行此测试类可以完美地解决问题。

问题是什么?我该如何解决?

5个回答

8
给您的测试类添加 @DirtiesContext 注解:
@ContextConfiguration(...)
@RunWith(...)
@DirtiesContext // <== add e.g. on class level
public class MyTest {
    // ...
}

这个注解表示与测试相关的应用程序上下文是脏的,需要关闭。后续的测试将会被提供一个新的上下文。该注解适用于类级别和方法级别。


1
问题是这发生在测试运行之后而不是之前。或者换句话说,我必须用这个注释标记每一个测试类才能使它工作。我需要的是类似于@RunInOwnContext的东西。 - beginner_
是的,这确实意味着您必须注释每个测试类...不幸的是,我不知道其他方法。 - jeha
当然,您可以尝试按照您的需求修改SpringJUnit4ClassRunner/TestContextManager...但我不确定那是否是您真正想要的。 - jeha
似乎没有其他方法,只能使用@DirtiesContext注释所有测试类。 - beginner_

7

我不知道这个问题是否仍然相关,但这里有一个简单/合适的解决方案(不需要在所有测试中添加@DirtiesContext)。避免@DirtiesContext允许您只拥有一个共享上下文来运行所有集成测试(例如通过maven运行或在IDE中运行所有测试)。这样可以避免由同时启动多个上下文引起的多个问题。

<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
  p:configLocation="ehcache.xml"
  p:cacheManagerName="myCacheManager"
  p:shared="${ehcacheManager.shared:true}"
  p:acceptExisting:"${ehcacheManager.acceptExisting:false}"/>

在你的测试(集成测试)中,设置这些属性。
ehcacheManager.acceptExisting=true
ehcacheManager.shared=false

它允许Spring为每个测试创建一个EhcacheManager(ehcache),但如果存在相同名称的EhcacheManager,则Spring将仅重用它。而且,Spring也不会在使用@DirtiesContext注释的上下文中销毁/关闭它。
这个想法很简单,您可以通过使用@DirtiesContext防止EhcacheManager被销毁。
如果您使用的是Spring 4和EhCache:2.5+,则可以使用此功能。对于Spring 3,您必须扩展EhCacheManagerFactoryBean以添加这两个属性。
在每个测试之前别忘了清除缓存 :)

p:acceptExisting应该是p:acceptExisting=,但是Stack Overflow不允许只有一个字符的编辑... - user472749

4

即使您的代码中有使用@Cacheable注释的方法,您也可以禁用缓存运行测试

这样,您就不需要将所有的测试标记为@DirtiesContext,从而避免了测试运行速度变慢。

与缓存相关的Spring配置放在单独的Spring配置文件中,例如applicationContext-cache.xml文件。

仅在实际运行应用程序时才包括applicationContext-cache.xml 文件,而不是在测试中包括它。

如果您特别想测试缓存,则需要使用@DirtiesContext注释。


我有带有@Cacheable注释的方法,因此必须始终存在一个CacheManager。 - beginner_
我正在运行没有CacheManager的测试,当运行测试时,缓存注释被忽略了。如果我想测试缓存功能,我会在测试设置中包含applicationContext-cache.xml,并将其标记为@DirtiesContext。 - Tero Hagström

1
这是因为在测试期间,存在多个Spring应用上下文。然而,ehcache是JVM全局的。
您可以通过在类路径上创建spring.properties文件来禁用Spring上下文缓存:
spring.test.context.cache.maxSize=1

确保当上下文被销毁时,缓存管理器已经被正确注销。


0

这解决了我的测试问题:

spring.cache.type=none

稍微详细一点的版本:

Julien Dubois:
我会直接使用 spring.cache.type=none,因为:

  • 它更简单
  • 它可以像以前的版本一样工作

我喜欢在测试时禁用缓存 - 当然这里可能会有很长的讨论 - 所以这也是我的最爱解决方案。

详细版本(不完全相同,但类似的问题):

阅读this


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接