Java 如何模拟类的方法';成员字段?

Java 如何模拟类的方法';成员字段?,java,mockito,Java,Mockito,我正在使用Java6和Mockito1.8.5。我想模拟类的成员字段的方法,但我不知道如何模拟。我有这些课程 public class CacheService implements CacheCallback { private final Cache cache; ... public static CacheService getInstance() { return INSTANCE; } private CacheService() { cache = new D

我正在使用Java6和Mockito1.8.5。我想模拟类的成员字段的方法,但我不知道如何模拟。我有这些课程

public class CacheService implements CacheCallback {

private final Cache cache;
...

public static CacheService getInstance() {
    return INSTANCE;
}

private CacheService() {
    cache = new DefaultCacheImpl();
}

public boolean saveNodes(final Map<Long, XmlNode> nodeMap) {
    ...
    cache.saveNodes(nodeMap);
}
...
}


public class DefaultCacheImpl implements Cache {
...
public void saveNodes(Map<Long, XmlNode> xmlNodes) {
    dao.updateDB(xmlNodes);
}
...
}
public类CacheService实现CacheCallback{
私有最终缓存;
...
公共静态缓存服务getInstance(){
返回实例;
}
专用缓存服务(){
cache=新的DefaultCacheImpl();
}
公共布尔存储节点(最终映射节点映射){
...
saveNodes(nodeMap);
}
...
}
公共类DefaultCacheImpl实现缓存{
...
公共void存储节点(映射xmlNodes){
dao.updateDB(xmlNodes);
}
...
}
我不知道如何模拟“cache”成员字段的方法“saveNodes”。我正在模拟下面的方法,但由于该字段的CacheService类中没有setter,因此我无法确定如何注入我的模拟

public class PopulateCacheServiceImpl extends RemoteServiceServlet implements PopulateCacheService {
...
public Boolean initCache() { 
    boolean ret = false;
    try {
        setupMocks();
        CacheService.getInstance().startCache();
        PopulateCache.addTestEntriesToCache();
        ret = true;
    } catch (Exception e) {
        e.printStackTrace(System.err);
        ret = false;
    }   // try
    return ret;
}   // initCache

private void setupMocks() { 
    DefaultCacheImpl cache = mock(DefaultCacheImpl.class);
    doAnswer(new Answer<Object>() {
        public Object answer(InvocationOnMock invocation) throws Throwable {
            return null;  
        }
    }).when(cache).saveNodes(Matchers.anyMap());
}   // setupMocks 

}
公共类PopulateCacheServiceImpl扩展RemoteServiceServlet实现PopulateCacheService{
...
公共布尔initCache(){
布尔ret=false;
试一试{
setupMocks();
CacheService.getInstance().startCache();
PopulateCache.addTestEntriesToCache();
ret=真;
}捕获(例外e){
e、 printStackTrace(System.err);
ret=假;
}//试试看
返回ret;
}//初始化缓存
私有void setupmock(){
DefaultCacheImpl cache=mock(DefaultCacheImpl.class);
doAnswer(新答案){
公共对象应答(InvocationMock调用)抛出Throwable{
返回null;
}
}).when(cache).saveNodes(Matchers.anyMap());
}//设置模拟
}

莫基托还有其他方法吗?谢谢,-Dave

问题出在这一行:

cache = new DefaultCacheImpl();
如果在CacheService中构造缓存对象,则它们是紧密耦合的。不能将CacheService与其他缓存实现一起使用

而是将缓存实现传递给构造函数:

public CacheService(Cache cacheImpl) {
    this.cache = cacheImpl;
}

这允许CacheService使用任何缓存实现。

如果可以更改源,请取消这些类的缓存。摆脱
cache=newdefaultcacheimpl()

如果不能,请使用PowerMock设置默认缓存impl
。我必须说这是一个非常丑陋的解决方案(唯一更丑陋的是模仿静态初始化代码)

注:
您的代码是对流行问题“为什么我需要依赖项注入?”。我认为当人们发明DI时,他们看到的是这样的代码。

制作两个构造函数怎么样?你的那个会留在那里。另一个可以让您传入缓存实现,并允许您测试该类。新的构造函数可以具有受保护的访问权限,以限制哪些类可以使用它。

感谢您的支持,但CacheService是一个单例,目前有一个私有构造函数。我可以改变源代码,但我仍然只想在JVM周围浮动CaseService类的一个实例。@ Dave You应该认真考虑避免对“代码> CaseService”(GestStand)()的静态依赖性,并使用适当的DI,这样您就不必在此处和那里进行黑客攻击来测试。您的设计也将更加干净和优雅。我对您所说的持开放态度,但我们的项目禁止在核心项目中使用第三方工具(如Spring)(用于测试其性能)。我无法与公司的政策抗争。请记住,我只希望JVM中有一个CacheService对象实例。我建议找出他们为什么如此反对第三方工具(可能是许可证问题或支持问题),并尝试改变他们的想法。或者找另一家准备让开发人员完成任务的公司。或者,如果做不到这一点,可以手动操作——您不需要工具,只需编写一个boostrapper,然后从那里开始运行您的类。请不要仅仅为了DI这样的小事而使用Spring这样的大型框架。我喜欢PowerMock的b/c思想,我不需要更改源代码。我的问题是我必须使用“PrepareForTest”注释吗?上面的类声明(“PopulateCacheServiceImpl”)不是JUnit测试类,而是由许多不同的测试间接调用的。您还可以使用PowerMock来模拟静态方法getInstance(),并返回一个模拟而不是单例。我不认为这有助于解决多个实例化点的问题。或者包私有而不是受保护。