2012-05-24 1 views
7

Я разрабатываю простую функциональность кеша с EhCache. Существует общий базовый класс, который реализует интерфейс мой кэш (BECache):Mocking net.sf.ehcache.Cache (ehcache) с .put методом заглушки (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); 
} 

Цель состоит в том, чтобы иметь кэши, определенные следующим образом:

public class ObjectCache extends EhCacheBase<String, Object>{ 

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

предполагая «cacheName» определяется в ehcache.xml Я получаю хороший класс для кэширования определенных объектов.

Я пытаюсь написать тест для «EhCacheBase.cache (...)» метод, который обеспечивает кэш извлекается и значение ставится (с использованием 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)); 
} 

Когда Я бег теста я получаю:

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) 

похоже, что «положить» метод в «кэше» издеваться называют некоторые другие методы. Но как вы можете прочитать в документах Mockito:

Используйте doNothing() для установки методов void, чтобы ничего не делать. Остерегайтесь, что void методы на mocks ничего не делают по умолчанию! Однако есть редкие ситуации, когда doNothing() пригодится:

Кстати, я пробовал: doNothing(). When (cache) .put (any (Element.class)); , и это тоже не помогло.

Любые идеи, что происходит?

+0

Потому что положить (Element) является окончательным, насмешливый это вопрос. – Zlatko

ответ

8

Cache.put является окончательным, поэтому вам нужно использовать PowerMock, если вы хотите издеваться над ним.

Ваш тест будет выглядеть следующим образом:

@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

Я отправил аналогичный вопрос в компанию Mockito Google Group (here). Я получил быстрый ответ от Эрика Лефевра-Арданта, который объяснил все. Метод net.sf.ehcache.Cache.put является окончательным, поэтому он не может быть заглушен - Mockito не может обеспечить свою собственную реализацию.

+0

Если это окончательно, вы можете высмеять это с помощью PowerMock, расширения для Mockito. –

2

Последняя версия Mockito (1.10.19) является not supported by PowerMock.

Вместо использования PowerMock, если возможно, другим решением является код для интерфейса net.sf.ehcache.Ehcache вместо реализации net.sf.ehcache.Cache.

Интерфейс Ehcache можно легко высмеять стандартным Mockito.

Я адаптированный пример принято отвечать в:

@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

Я считаю, что это должен быть правильный ответ – spekdrum