【问题标题】:Mocking net.sf.ehcache.Cache (ehcache) with .put method stub (Mockito)使用 .put 方法存根 (Mockito) 模拟 net.sf.ehcache.Cache (ehcache)
【发布时间】:2012-05-24 19:06:03
【问题描述】:

我正在使用 EhCache 开发一个简单的缓存功能。 有一个通用基类实现了我的缓存接口(BECache):

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)

'cache' 模拟中的 'put' 方法似乎正在调用其他一些方法。 但正如您可以在 Mockito 文档中看到的那样:

使用 doNothing() 将 void 方法设置为不执行任何操作。请注意,模拟上的 void 方法默认情况下什么都不做! 但是,doNothing() 派上用场的情况很少见:

顺便说一句,我试过:doNothing().when(cache).put(any(Element.class)); 它也没有帮助。

有什么想法吗?

【问题讨论】:

  • 因为 put(Element) 是最终的,所以模拟它是一个问题。
  • get(stringName)也是如此

标签: java mocking ehcache mockito


【解决方案1】:

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));
    }
}

【讨论】:

    【解决方案2】:

    我向 Mockito Google Group (here) 发布了一个类似的问题。我得到了 Eric Lefevre-Ardant 的快速回复,解释了一切。 net.sf.ehcache.Cache.put 方法是最终方法,因此不能被存根 - Mockito 无法提供自己的实现。

    【讨论】:

    • 如果它是最终版本,您可以使用 PowerMock(Mockito 的扩展)来模拟它。
    【解决方案3】:

    最新版本的 Mockito (1.10.19) 是 not supported by PowerMock

    如果可能,另一种解决方案是编写net.sf.ehcache.Ehcache 接口而不是net.sf.ehcache.Cache 实现,而不是使用PowerMock。

    使用标准 Mockito 可以轻松地模拟 Ehcache 接口。

    我已经修改了接受的答案的例子:

    @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));
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-13
      • 2023-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多