我有一个抽象缓存客户端,它有一个实现,我试图向其中添加单元测试,它有一个键的受保护类实现。
public abstract class SimpleCacheClient<V extends Serializable> {
// Autowired RedissonClient and RedisKeyGenerator
public V get(SimpleCacheKey key) {
// return the cache entry from the autowired RedissonClient
}
public void set(SimpleCacheKey key, V value) {
// set the cache entry
}
public SimpleCacheKey getCacheKey(Object...keys) {
return new SimpleCacheKey(keyGenerator.generateKey(keys));
}
/**
* Simple wrapper for cache key to guarantee that implementations
* are using the key generator provided in this class
*/
protected class SimpleCacheKey {
private String key;
SimpleCacheKey(String key) {
this.key = key;
}
public String getKey() {
return key;
}
@Override
public String toString() {
return getKey();
}
}
}
下面是我尝试测试的实现:
public class CacheClientImplementation extends SimpleCacheClient<ArrayList<DateTime>> {
public void addEventDateTimes(String key, ArrayList<DateTime> eventDateTimes) {
// Do stuff with eventDateTimes and then
set(getCacheKey(key), eventDateTimes);
}
public ArrayList<DateTime> getEventDateTimes(String key) {
ArrayList<DateTime> eventDateTimes = get(getCacheKey(key));
// Do stuff with eventDateTimes.
return eventDateTimes;
}
}
我尝试测试以确保CacheClientImplementation
在设置和获取之前对提供给它的值执行特定的操作。我尝试通过劫持get()
和set()
方法来模拟redis缓存本身,以便在测试中检查“缓存”的内容。
@RunWith(MockitoJUnitRunner.class)
public class CacheClientImplementationTest{
@Mock
private RedissonClient redissonClient;
@Mock
private RedisKeyGenerator redisKeyGenerator;
@Spy
@InjectMocks
private CacheClientImplementation cacheClient = new CacheClientImplementation();
private final HashMap<String, ArrayList<DateTime>> cacheMap = new HashMap<>();
@Before
public void setup() {
Mockito.doAnswer((ver) -> {
cacheMap.put(ver.getArgumentAt(0, Object.class).toString(), ver.getArgumentAt(1, ArrayList.class));
return null;
}).when(cacheClient).set(Mockito.any(), Mockito.any(ArrayList.class));
Mockito.doAnswer((ver) -> cacheMap.getOrDefault(ver.getArgumentAt(0, Object.class).toString(), null))
.when(cacheClient).get(Mockito.any());
}
@After
public void teardown() {
cacheMap.clear();
}
}
但是,当我在文件中运行测试时,我最终遇到了这个问题。
C:\...\CacheClientImplementationTest.java:20: error: SimpleCacheClient.SimpleCacheKey has protected access in SimpleCacheClient
}).when(cacheClient).set(Mockito.any(), Mockito.any(ArrayList.class));
有没有什么方法可以在不改变SimpleCacheKey的情况下对这些方法执行doAnswer
?
谢谢你!
1条答案
按热度按时间cpjpxq1n1#
这归结为
SimpleCacheKey
类的可见性,你不能从不同的包中使用它,所以Mockito.any()
不能使用该类作为返回类型,除非单元测试和SimpleCacheClient
在同一个包中。一种解决方案是将单元测试移到
SimpleCacheClient
所在的包中。如果这是从一个不同的库中加载的,而您无法更改它,那么您可以重新创建相同的包结构来欺骗编译器,使其认为该包是相同的,从而允许您访问protected
类。但我相信这种技巧在Java 9模块中不起作用。一个更好的解决方案是对
CacheClientImplementation
和单元测试做一个小的修改;把你无法影响的部分封装起来并嘲笑它。由于您实际上并不关心
SimpleCacheKey
,而只关心String key
,因此以下内容应该符合您的意图:在单元测试中,您将重写为我们刚刚创建的
forKey
变体:我已经创建了新的方法
protected
,以便不会混淆调用者使用哪个方法,所以在本例中,单元测试必须与CacheClientImplementation
在同一个(测试)包中。