So I have began using JMockit and JUnit to test my code.
I wrote a class and wanted to test that class. The class is as follows -
public final class KingdomDAOImpl implements KingdomDAO {
private Map<KingdomType, Kingdom> kingdomEmblemMap;
@Inject
public KingdomDAOImpl(final Map<KingdomType, Kingdom> kingdomEmblemMap) {
this.kingdomEmblemMap = kingdomEmblemMap;
}
@Override
public Map<KingdomType, Kingdom> getKingdoms() {
return kingdomEmblemMap;
}
}
And my test class looks like this -
public class KingdomDAOTest {
@Injectable
private static Map<KingdomType, Kingdom> kingdomEmblemMap;
@Tested
private static KingdomDAOImpl kingdomDAO;
@BeforeClass
public static void beforeClass() {
kingdomEmblemMap = new HashMap<>();
}
@Test
public void getKingdomsTest() {
System.out.println("=========+> " + kingdomDAO);
final Map<KingdomType, Kingdom> actualKingdomEmblemMap = kingdomDAO.getKingdoms();
Assert.assertEquals(kingdomEmblemMap, actualKingdomEmblemMap);
}
}
Now, the problem that I'm having is that the kingdomDAO
instance is null
, which I am not able to understand why. Due to this, kindomDAO.getKingdoms()
throws a NullPointerException
.
Any ideas on how to proceed from here?
EDIT: I was using JMockit version 1.8
. I have tried upgrading to 1.45
and replacing @Injectable
annotation with @Tested
, but still the same problem persists.
JMockit has changed a bit since the last time I used it.
What I can recommend to you is, always read the release notes!
Version 1.42
JMockit now requires the use of the "-javaagent" JVM initialization parameter
Version 1.45
Mocking annotations (@Mocked, @Capturing, and @Injectable) can no longer be used on Java SE collection and map interfaces, for two reasons: 1) on Java 8+, such interfaces include default methods, which do get mocked, easily causing unexpected results in tests; 2) mocking of said interfaces (and more generally, of all value-oriented types which basically encapsulate state without complex behavior in methods) is a well known bad practice. In the particular case of having an @Injectable collection/map field which is meant to be injected into a @Tested object, the test should be changed to use @Tested as well on the collection/map field, with its declaration positioned before the target @Tested field.
Although I wouldn't code a test like that, the working example is:
public class KingdomDAOtest {
@Tested
Map<KingdomType, Kingdom> kingdomEmblemMap = new HashMap<>();
@Tested
KingdomDAOImpl kingdomDAO;
@Test
public void getKingdomsTest() {
System.out.println("=========+> " + kingdomDAO);
final Map<KingdomType, Kingdom> actualKingdomEmblemMap = kingdomDAO.getKingdoms();
Assert.assertEquals(kingdomEmblemMap, actualKingdomEmblemMap);
}
}