I've come across what I think is an issue with generics. Below is a self-contained test that demonstrates the problem. The method test1() runs fine whereas test2() throws a ClassCastException which I think should not happen:
package playground;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import mockit.Expectations;
import mockit.Mocked;
public class PlayTest {
static interface User { public String getUserId(); }
static interface UserConfig { Map<String, String> getUserConfigs(); }
static class UserRepo {
Map<String, User> userCache;
Map<String, UserConfig> userConfigCache;
public User getUser(String key) {
return userCache.get(key);
}
public Map<String, String> getPreferences(String key) {
final User user = userCache.get(key);
if (user != null) {
final String userId = user.getUserId();
final UserConfig userConfig = userConfigCache.get(userId);
if (userConfig != null) {
return Collections.unmodifiableMap(userConfig.getUserConfigs());
}
}
return Collections.emptyMap();
}
}
@Mocked Map<String, User> userCache;
@Mocked Map<String, UserConfig> userConfigCache;
@Mocked User user;
UserRepo userRepo;
@Before
public void setup() {
userRepo = new UserRepo();
userRepo.userCache = userCache;
userRepo.userConfigCache = userConfigCache;
}
@Test
public void test1() {
final String userName = "fooUser";
final String userId = "123456";
final Map<String,String> prefs = new HashMap<>();
prefs.put("foo", "bar");
final UserConfig userConfig = new UserConfig() {
@Override
public Map<String, String> getUserConfigs() {
return prefs;
}
};
new Expectations() /* @formatter:off */ {{
userCache.get(userName); result = user;
user.getUserId(); result = userId;
userConfigCache.get(userId); result = userConfig;
}}; // @formatter:on
final Map<String, String> preferences = userRepo.getPreferences(userName);
Assert.assertNotNull(preferences);
Assert.assertFalse(preferences.isEmpty());
}
@Test
public void test2() {
final String userName = "fooUser";
final String userId = "123456";
new Expectations() /* @formatter:off */ {{
userCache.get(userName); result = user;
user.getUserId(); result = userId;
// UNCOMMENT TO FIX: userConfigCache.get(userId); result = null;
}}; // @formatter:on
final Map<String, String> preferences = userRepo.getPreferences(userName);
Assert.assertNotNull(preferences);
Assert.assertTrue(preferences.isEmpty());
}
static interface CustomMap<K, V> {
V get(K userId);
}
}
Basically what is happening is this: I am mocking the type Map for these two variables:
It appears to me that when JMockIt initializes these two mocks, it erroneously picks up the type parameters of the first declaration and associates them with both mock instances. It remains in that incorrect state until you configure explicit expectations for the mocks.
If you happen to write a test that doesn't explicitly set a return value (i.e. rely on the default behavior of returning null) you get a class cast exception.
As you can see test2() can be fixed by simply removing the commented out line:
// UNCOMMENT TO FIX: userConfigCache.get(userId); result = null;
Without this line you get:
java.lang.ClassCastException: playground.$Proxy6 cannot be cast to playground.PlayTest$UserConfig
at playground.PlayTest$UserRepo.getPreferences(PlayTest.java:30)
at playground.PlayTest.test2(PlayTest.java:87)
...
The text was updated successfully, but these errors were encountered:
karypid
changed the title
ClassCastException in paremetrized type
ClassCastException in paremetrized type (tried with 1.28 and 1.31)
Apr 21, 2017
Hello,
I've come across what I think is an issue with generics. Below is a self-contained test that demonstrates the problem. The method test1() runs fine whereas test2() throws a ClassCastException which I think should not happen:
Basically what is happening is this: I am mocking the type Map for these two variables:
It appears to me that when JMockIt initializes these two mocks, it erroneously picks up the type parameters of the first declaration and associates them with both mock instances. It remains in that incorrect state until you configure explicit expectations for the mocks.
If you happen to write a test that doesn't explicitly set a return value (i.e. rely on the default behavior of returning null) you get a class cast exception.
As you can see test2() can be fixed by simply removing the commented out line:
Without this line you get:
The text was updated successfully, but these errors were encountered: