9

Before you mark this as duplicate please read the question first. I've read all the stuff about this exception however it does not solve the issue for me. And I do get a slightly different exception eg Another CacheManager with same name 'myCacheManager' already exists instead of Another unnamed CacheManager already exists.

Spring config:

<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>

The Problem is that I have 1 (in the future more) test classes that test security. these classes also load a SecurityContext.xml

So most test classes have this annotations:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:ApplicationContext.xml")

However the class causing the issue:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
    "classpath:ApplicationContext.xml",
    "classpath:SecurityContext.xml"
})

It seems since locations are different the context is loaded again but ehcacheManager is still active from previous test.

Note: this happens only when running multiple tests (eg. like clean + build). Running this test class separately works perfectly fine.

Whats the issue? How can I solve it?

beginner_
  • 7,230
  • 18
  • 70
  • 127

5 Answers5

8

Add @DirtiesContext annotation to your test class:

@ContextConfiguration(...)
@RunWith(...)
@DirtiesContext // <== add e.g. on class level
public class MyTest {
    // ...
}

This annotation indicates that the application context associated with a test is dirty and should be closed. Subsequent tests will be supplied a new context. Works on class-level and method-level.

jeha
  • 10,562
  • 5
  • 50
  • 69
  • 1
    Problem is that this happens after the test is run not before. Or said otherwise I would have to mark every single test class with this annotation to make it work. What i would need is something like @RunInOwnContext. – beginner_ Feb 23 '13 at 13:30
  • Yes, it indeed means you have to annotate every test class ... unfortunately there is no other way I'm aware of. – jeha Feb 23 '13 at 14:06
  • Of course you try to modify SpringJUnit4ClassRunner / TestContextManager in the way you need it ... but I don't know if that's what you really want – jeha Feb 23 '13 at 14:15
  • marked as answer. There seems to be no other way than to annotate all Test classes with @DirtiesContext. – beginner_ Mar 14 '13 at 16:22
7

I don't know if the question/issue are still relevent, but here's a simple/proper solution (Don't need to add @DirtiesContext in all your tests). Avoid @DirtiesContext allows you to have only one shared context for all integration tests (via run by maven for example, or run all tests in an IDE). That avoids multiple problems caused by multiple contexts started in same times.

<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}"/>

In your tests (integration tests), set those properties

ehcacheManager.acceptExisting=true
ehcacheManager.shared=false

It allows Spring to create an EhcacheManager (ehcache) for each test, but if an EhcacheManager with the same name exist, Spring will just reuse it. And Spring will also not destroy/shutdown it in the context annotated with @DirtiesContext.

The idea is simple, you prevent the destroy of EhcacheManager when using @DirtiesContext.

It's applicable if you use Spring 4 and EhCache:2.5+. With Spring 3, you must an extends of EhCacheManagerFactoryBean to add these two properties.

Don't forget to clear your cache before each test :)

khong07
  • 316
  • 1
  • 4
  • 10
4

You can run your tests with caching disabled even if your code has methods with @Cacheable annotations.

That way you do not have to slow your test run down by marking all of your tests with @DirtiesContext.

Put the cache related Spring configurations in their own Spring config file, eg. applicationContext-cache.xml file.

Include that applicationContext-cache.xml file only when running the application live, but not in your tests.

If you specifically want to test caching, then you need the @DirtiesContext annotation.

Tero Hagström
  • 131
  • 2
  • 2
  • I have methods with @Cacheable annotation and hence a CacheManager must always be present. – beginner_ Jun 26 '14 at 05:00
  • I'm running tests without a CacheManager, and the caching annotations are being ignored when running the tests. If I wanted to test the cache functionality, I would include applicationContext-cache.xml in the test setup, and also mark it with @DirtiesContext. – Tero Hagström Jun 30 '14 at 11:50
1

This happens because during testing, there are ultiple Spring application contexts existing at the same time. However, ehcache is JVM-global.

You can essentially disable Spring context caching, by creating spring.properties file on your classpath:

spring.test.context.cache.maxSize=1

Make sure that the cache manager is properly unregistered when a context is destroyed.

Mateusz Stefek
  • 173
  • 1
  • 6
0

This solved my testing issue:

spring.cache.type=none

Slightly longer version:

Julien Dubois:
I would just do spring.cache.type=none as:

  • it's much simpler
  • it would work as in the previous versions

I prefer to have the cache disabled when I do my tests - then of course there could be a very long discussion here - so that's also my favorite solution.

Detailed version (not exactly same, but similar issue):

Read this.

jumping_monkey
  • 5,941
  • 2
  • 43
  • 58