2012-05-24 20 views
7

Estoy desarrollando una funcionalidad de caché simple con EhCache. Hay una clase base genérica que implementa la interfaz de mi caché (BECache):Mocking net.sf.ehcache.Cache (ehcache) con .put method stub (Mockito)

public class EhCacheBase<K, V> implements BECache<K, V> { 

private static CacheManager cacheManager; 
private String cacheName; 

public EhCacheBase(String cacheName) { 
    this.cacheName = cacheName; 
} 

public void cache(K key, V value) { 
    Cache cache = cacheManager.getCache(cacheName); 
    if (cache == null) { 
     throw new NullPointerException("Failed to obtain cache: " + cacheName); 
    } 
    Element element = new Element(key, value); 
    cache.put(element); 
} 

El propósito es tener cachés definidos de la siguiente manera:

public class ObjectCache extends EhCacheBase<String, Object>{ 

    public ObjectCache (String cacheName) { 
     super(cacheName); 
    } 
} 

suponiendo 'cacheName' se define en ehcache.xml Obtengo una buena clase para almacenando en caché ciertos objetos.

Estoy intentando escribir una prueba para el método 'EhCacheBase.cache (...)' que asegura se recupera una memoria caché y se pone un valor (utilizando Mockito):

private static final String CACHE_NAME = "testCache"; 
@Mock 
private CacheManager cacheManager; 
@Mock 
private Cache cache; 
private EhCacheBase<String, Object> ehCacheBase; 

@Before 
public void init() { 
    MockitoAnnotations.initMocks(this); 
    ehCacheBase = new EhCacheBase<String, Object>(CACHE_NAME); 
    EhCacheBase.setCacheManager(cacheManager); 
} 

@Test 
public void shouldRetrieveCacheAndPutOneValueInIt() { 
    //given 
    Object o = new Object(); 
    when(cacheManager.getCache(CACHE_NAME)).thenReturn(cache); 

    //when 
    ehCacheBase.cache("KEY", o); 

    //then 
    verify(cacheManager, times(1)).getCache(CACHE_NAME); 
    verify(cache, times(1)).put(any(Element.class)); 
} 

Cuando funciono con la prueba de recibo:

java.lang.NullPointerException 
    at net.sf.ehcache.Cache.checkStatus(Cache.java:2731) 
    at net.sf.ehcache.Cache.putInternal(Cache.java:1440) 
    at net.sf.ehcache.Cache.put(Cache.java:1417) 
    at net.sf.ehcache.Cache.put(Cache.java:1382) 
    at org.fxoo.bookingengine.dao.dataproviders.caches.EhCacheBase.cache(EhCacheBase.java:24) 
    at org.fxoo.bookingengine.dao.dataproviders.caches.EhCacheBaseTest.shouldCacheOneValue(EhCacheBaseTest.java:41) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45) 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) 
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42) 
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) 
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) 
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300) 
    at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:35) 
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:115) 
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:97) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at org.apache.maven.surefire.booter.ProviderFactory$ClassLoaderProxy.invoke(ProviderFactory.java:103) 
    at $Proxy0.invoke(Unknown Source) 
    at org.apache.maven.surefire.booter.SurefireStarter.invokeProvider(SurefireStarter.java:150) 
    at org.apache.maven.surefire.booter.SurefireStarter.runSuitesInProcess(SurefireStarter.java:91) 
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:69) 

parece que el método de 'poner' en simulacro 'caché' está llamando a algunos otros métodos. Pero como puede leer en los documentos de Mockito:

Use doNothing() para configurar los métodos vacíos para que no hagan nada. Tenga cuidado de que los métodos nulos en los simulacros no hagan nada por defecto. Sin embargo, existen situaciones excepcionales en las que no resulta útil DoNothing():

Por cierto, probé: doNothing(). When (cache) .put (any (Element.class)); y tampoco ayudó.

¿Alguna idea de lo que está pasando?

+0

Debido put (Element) es final, burlándose de que es un problema. – Zlatko

Respuesta

8

Cache.put es final, por lo que necesita utilizar PowerMock si desea simularlo.

Su prueba se vería así:

@RunWith(PowerMockRunner.class) 
@PrepareForTest(Cache.class) 
public class EhCacheBaseTest { 
    private static final String CACHE_NAME = "testCache"; 
    private CacheManager cacheManager; 
    private Cache cache; 
    private EhCacheBase<String, Object> ehCacheBase; 

    @Before 
    public void init() { 
     // You can statically import mock method, but left it this way 
     // for clarity 
     cacheManager = PowerMockito.mock(CacheManager.class); 
     cache = PowerMockito.mock(Cache.class); 
     ehCacheBase = new EhCacheBase<String, Object>(CACHE_NAME); 
     EhCacheBase.setCacheManager(cacheManager); 
    } 

    @Test 
    public void shouldRetrieveCacheAndPutOneValueInIt() { 
     //given 
     Object o = new Object(); 
     when(cacheManager.getCache(CACHE_NAME)).thenReturn(cache); 

     //when 
     ehCacheBase.cache("KEY", o); 

     //then 
     verify(cacheManager, times(1)).getCache(CACHE_NAME); 
     verify(cache, times(1)).put(any(Element.class)); 
    } 
} 
3

He publicado una pregunta similar a Mockito Google Group (here). Recibí una respuesta rápida de Eric Lefevre-Ardant que me explicó todo. El método net.sf.ehcache.Cache.put es definitivo, por lo que no se puede anular: Mockito no proporciona su propia implementación.

+0

Si es final, puede burlarse de él con PowerMock, una extensión de Mockito. –

2

La última versión de Mockito (01/10/19) es not supported by PowerMock.

En lugar de utilizar PowerMock, si es posible, otra solución es codificar en la interfaz net.sf.ehcache.Ehcache en lugar de la implementación net.sf.ehcache.Cache.

La interfaz de Ehcache se puede burlar fácilmente con Mockito estándar.

He adaptado el ejemplo de la respuesta aceptada:

@RunWith(MockitoJUnitRunner.class) 
public class EhCacheBaseTest { 
    private static final String CACHE_NAME = "testCache"; 

    @Mock private Ehcache cache; 
    @Mock private CacheManager cacheManager; 

    private EhCacheBase<String, Object> ehCacheBase; 

    @Before 
    public void init() { 
     ehCacheBase = new EhCacheBase<String, Object>(CACHE_NAME); 
     EhCacheBase.setCacheManager(cacheManager); 
    } 

    @Test 
    public void shouldRetrieveCacheAndPutOneValueInIt() { 
     //given 
     Object o = new Object(); 
     when(cacheManager.getEhcache(CACHE_NAME)).thenReturn(cache); 

     //when 
     ehCacheBase.cache("KEY", o); 

     //then 
     verify(cacheManager, times(1)).getEhcache(CACHE_NAME); 
     verify(cache, times(1)).put(any(Element.class)); 
    } 
} 
+0

Creo que esta debería ser la respuesta correcta – spekdrum