I’m writing unit test for my CacheService
class:
public class CacheService {
private final HashOperations<String, String, String> redisHashOps;
private final ValueOperations<String, String> valueOps;
private final SetOperations<String, String> setOps;
public CacheService(StringRedisTemplate redisTemplate) {
this.redisHashOps = redisTemplate.opsForHash();
this.valueOps = redisTemplate.opsForValue();
this.setOps = redisTemplate.opsForSet();
}
Unit test:
public class CacheServiceTest {
private CacheService cacheService;
private HashOperations<String, String, String> redisHashOps;
private ValueOperations<String, String> redisValueOps;
private SetOperations<String, String> redisSetOps;
@BeforeEach
public void setUp() {
final StringRedisTemplate redisTemplate = mock(StringRedisTemplate.class);
redisValueOps = mock(ValueOperations.class);
redisHashOps = mock(HashOperations.class);
redisSetOps = mock(SetOperations.class);
when(redisTemplate.opsForValue()).thenReturn(redisValueOps);
when(redisTemplate.opsForHash()).thenReturn(redisHashOps);
when(redisTemplate.opsForSet()).thenReturn(redisSetOps);
redisValueOps
and redisSetOps
have no problem, but for redisHashOps
, the IDE prompts:
If I build the project will see following error:
java: no suitable method found for thenReturn(org.springframework.data.redis.core.HashOperations<java.lang.String,java.lang.String,java.lang.String>)
method org.mockito.stubbing.OngoingStubbing.thenReturn(org.springframework.data.redis.core.HashOperations<java.lang.String,java.lang.Object,java.lang.Object>) is not applicable
(argument mismatch; org.springframework.data.redis.core.HashOperations<java.lang.String,java.lang.String,java.lang.String> cannot be converted to org.springframework.data.redis.core.HashOperations<java.lang.String,java.lang.Object,java.lang.Object>)
method org.mockito.stubbing.OngoingStubbing.thenReturn(org.springframework.data.redis.core.HashOperations<java.lang.String,java.lang.Object,java.lang.Object>,org.springframework.data.redis.core.HashOperations<java.lang.String,java.lang.Object,java.lang.Object>...) is not applicable
(argument mismatch; org.springframework.data.redis.core.HashOperations<java.lang.String,java.lang.String,java.lang.String> cannot be converted to org.springframework.data.redis.core.HashOperations<java.lang.String,java.lang.Object,java.lang.Object>)
Looking at RedisTemplate’s source code, I found the difference between opsForHash and opsForValue:
public <HK, HV> HashOperations<K, HK, HV> opsForHash() ...
public ValueOperations<K, V> opsForValue() ...
How to modify the unit test to make it working?
2
Answers
You can rewrite your mock expectations using
doReturn
instead:You found it right:
In the first (and last) case
<K, V>
refers toRedisTemplate
generic parameters (which are assigned to<String, String>
here).In case of
<HK, HV> HashOperations<K, HK, HV>
, theK
is "safe again", but<HK, HV>
are "method generic parameters", which the compiler cannot infer here.Solutions:
we free the compiler from guessing.