PlayFramework: overriding a @NamedCache in Tests

The PlayFramework documentation states on how to override a simple binding of a Class in your Guice Tests to another implementation, like this:

Application application = new GuiceApplicationBuilder()
    .overrides(bind(Component.class).to(MockComponent.class))
    .build();

If you’re using the CacheApi in your tests, you might stumble upon this kind of error:

Error in custom provider, net.sf.ehcache.ObjectExistsException: Cache cmsCache already exists
 at play.api.cache.EhCacheModule.play$api$cache$EhCacheModule$$bindCache$1(Cache.scala:178):
Binding(interface net.sf.ehcache.Ehcache qualified with QualifierInstance(@play.cache.NamedCache(value=cmsCache)) to ProviderTarget(play.api.cache.NamedEhCacheProvider@77f743af)) (via modules: com.google.inject.util.Modules$OverrideModule -> play.api.inject.guice.GuiceableModuleConversions$$anon$1)
 while locating net.sf.ehcache.Ehcache annotated with @play.cache.NamedCache(value=cmsCache)
 at play.api.cache.EhCacheModule.play$api$cache$EhCacheModule$$bindCache$1(Cache.scala:179):
Binding(interface play.api.cache.CacheApi qualified with QualifierInstance(@play.cache.NamedCache(value=cmsCache)) to ProviderTarget(play.api.cache.NamedCacheApiProvider@23f72489)) (via modules: com.google.inject.util.Modules$OverrideModule -> play.api.inject.guice.GuiceableModuleConversions$$anon$1)
 while locating play.api.cache.CacheApi annotated with @play.cache.NamedCache(value=cmsCache)
 at play.api.cache.EhCacheModule.play$api$cache$EhCacheModule$$bindCache$1(Cache.scala:180):
Binding(interface play.cache.CacheApi qualified with QualifierInstance(@play.cache.NamedCache(value=cmsCache)) to ProviderTarget(play.api.cache.NamedJavaCacheApiProvider@100cf07)) (via modules: com.google.inject.util.Modules$OverrideModule -> play.api.inject.guice.GuiceableModuleConversions$$anon$1)

to fix this error, create first a FakeCacheApi Class for your tests like this:

public class FakeCacheApi implements CacheApi {

    private HashMap<String, Object> data = new HashMap<>();


    @Override
    public <T> T get(String s) {
        return (T) data.get(s);
    }

    @Override
    public <T> T getOrElse(String s, Callable<T> callable, int i) {
        return getOrElse(s, callable);
    }

    @Override
    public <T> T getOrElse(String s, Callable<T> callable) {
        if (data.containsKey(s)) {
            return (T) data.get(s);
        } else {
            try {
                T value = callable.call();
                return value;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    }

    @Override
    public void set(String s, Object o, int i) {
        data.put(s, o);
    }

    @Override
    public void set(String s, Object o) {
        data.put(s, o);
    }

    @Override
    public void remove(String s) {
        data.remove(s);
    }
}

and then override the bindings in your tests like this:

import play.cache.NamedCacheImpl;
....
Application application = new GuiceApplicationBuilder() .overrides(
bind(CacheApi.class).to(FakeCacheApi.class),
bind(CacheApi.class).qualifiedWith(new NamedCacheImpl("cmsCache")).to(FakeCacheApi.class) // repeat this line for every named cache you have
).build();

Leave a comment

Your email address will not be published. Required fields are marked *