简体   繁体   English

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

[英]How do I mock a method of a class' member field?

I'm using Java 6 and Mockito 1.8.5. 我正在使用Java 6和Mockito 1.8.5。 I want to mock a class' member field's method, but I can't figure out how. 我想模拟一个类'成员字段的方法,但我无法弄清楚如何。 I have these classes ... 我有这些课......

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

I can't figure out how to mock the "cache" member field's method "saveNodes". 我无法弄清楚如何模拟“缓存”成员字段的方法“saveNodes”。 I'm mocking the method below, but because there is no setter in the CacheService class for the field, I can't figure out how to inject my mock .. 我正在嘲笑下面的方法,但因为该字段的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 

}

Are there any other ways to do this with Mockito? Mockito有没有其他方法可以做到这一点? Thanks, - Dave 谢谢, - 戴夫

The problem is in this line: 问题出在这一行:

cache = new DefaultCacheImpl();

If you construct a cache object inside your CacheService, they are tightly coupled. 如果在CacheService中构造一个缓存对象,它们是紧密耦合的。 You can not use the CacheService with another cache implementation. 您不能将CacheService与另一个缓存实现一起使用。

Instead, pass the cache implementation to the constructor: 相反,将缓存实现传递给构造函数:

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

This allows the CacheService to use any Cache implementation. 这允许CacheService使用任何Cache实现。

What about making two constructors? 如何制作两个构造函数? The one you have would stay there. 你拥有的那个会留在那里。 Another one would let you pass in the Cache implementation and allow you to test the class. 另一个允许您传递Cache实现并允许您测试该类。 The new constructor can have protected access to limit which classes can use it. 新构造函数可以具有受保护的访问权限,以限制哪些类可以使用它。

If you can change the source, decopule those classes. 如果您可以更改源,请对这些类进行decopule。 Get rid of cache = new DefaultCacheImpl(); 摆脱cache = new DefaultCacheImpl(); from constructor as Sjoerd suggested. 来自Sjoerd建议的构造函数。

If you can't - use PowerMock to mock the constructor of DefaultCacheImpl . 如果你不能 - 使用PowerMock来模拟 DefaultCacheImpl 的构造函数 I must say that this is really ugly solution (the only uglier is mocking static initialization code). 我必须说这是一个非常丑陋的解决方案(唯一丑陋的是模拟静态初始化代码)。

Note: Your code is an answer to popular question "Why do I need dependency injection for?". 注意:您的代码是对流行问题“为什么我需要依赖注入?”的回答。 I think people were looking at code like this when they invented DI. 我认为人们在发明DI时会看到这样的代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM