2012-05-24 59 views
7

我正在開發用了Ehcache簡單的緩存功能。 有實現我的高速緩存接口(BECache)的通用基類:嘲諷net.sf.ehcache.Cache(的Ehcache)用。把方法存根(的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中定義我爲 緩存某些對象獲得了不錯的課程。

我想寫爲確保 緩存檢索和值放入(使用的Mockito)的「EhCacheBase.cache(...)」方法測試:

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) 

看起來'緩存'模擬中的'put'方法正在調用其他一些方法。 但是,正如你可以在Mockito文檔中閱讀:

使用doNothing()來設置void方法什麼都不做。請注意,mock上的無效方法在默認情況下不會做任何事情!然而,在doNothing()方便的情況下很少見:

順便說一句,我試過:doNothing()。when(cache).put(any(Element.class)); 也沒有幫助。

任何想法是怎麼回事?

+0

由於認沽(元)是最後的,嘲諷這是一個問題。 – 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集團(here)。我得到了Eric Lefevre-Ardant的一個快速回應,解釋了一切。 net.sf.ehcache.Cache.put方法是final的,所以它不能被存根 - Mockito不能提供它自己的實現。

+0

如果它是最終的,你可以用PowerMock來模擬它,它是Mockito的擴展。 –

2

的的Mockito最新版本(19年1月10日)是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