PowerMockito Enum in Switch Statement throwing NPE - java

I'm testing a class with PowerMockRunner which retrieves a value ENUM from a static method in a helper class. A null pointer is thrown when this value ENUM is passed into a SWITCH statement in the classUnderTest.
I've debugged and can see the ENUM is set correctly (name, type, ordinal all as expected) so am unsure as to why the NPE is thrown. Anybody encounter similar issue?
Note: PowerMockito is required as classUnderTest includes calls to private methods. Below is complete example with a lot of code (unrelated to issue) removed. Comments added at point where ENUM is set and NPE is thrown
ClassUnderTest:
public class TestService extends BaseXAServiceBean
{
#Override
public ValueObject runExecute(ValueObject param) throws RemoteException, ServiceException
{
try
{
ValueEnum value = ValueServiceHelper.getValueType(param1(),
param2());
// value populated successfully with ENUM at this point
// NPE thrown when value is passed into below switch
switch (value)
{
case VALUE1:
{
// logic here...
break;
}
case VALUE2:
{
// logic here...
break;
}
case VALUE3:
{
// logic here...
break;
}
}
}
catch (ServiceException e)
{
throw e;
}
catch (Exception e)
{
throw new ServiceException(e, AppErrorCodes.INT.SL06, AppErrorCodes.SL06.E04);
} finally {
// clean up
}
}
}
Helper Class with static method:
public class ValueServiceHelper
{
public static ValueEnum getValueType(String param1, String param2) throws ServiceException
{
ValueEnum retVal = ValueEnum.VALUE3;
// proxy is mocked
ProductProxy proxy = ProxyFactory.createFactory("1").getProductProxy();
try
{
if (proxy.isValue1(param2))
{
retVal = ValueEnum.VALUE1;
}
else if (proxy.isValue2(param2))
{
retVal = ValueEnum.VALUE2;
}
}
return retVal;
}
}
Test Class:
#RunWith(PowerMockRunner.class)
#PrepareForTest({ProxyFactory.class})
public class ValueTest {
#Spy
#InjectMocks
private TestService service = new TestService();
#Mock
private ProxyFactory proxyFactory;
#Mock
private Proxy proxy;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
PowerMockito.mockStatic(ProxyFactory.class);
}
#Test
public void testSuccess() throws Exception {
// given
// when
PowerMockito.when(ProxyFactory.createFactory("1")).thenReturn(proxyFactory);
PowerMockito.when(proxyFactory.getProductProxy()).thenReturn(proxy);
PowerMockito.when(proxy.isValue1(param2)).thenReturn(true);
PowerMockito.when(proxy.isValue2(param2)).thenReturn(true);
service.runExecute(request);
// then
}
}

This is an issue with PowerMock that has existed since at least 2015. The only way to fix it that I'm aware of is to use if statements instead of a switch.

Related

Mockito test to throw RuntimeException on 3rd call to a void method

UPDATED QUESTION TO CLARIFY
I have a class with a void method. This method will call a service which will lock user after X failed attempts to unlock a door.
Here are my classes:
#Stateless(name = "DoorServiceEjb")
public class DoorServiceEjb {
private static final int EXPIRY_PERIOD = 1;
private static final int MAX_ATTEMPTS = 3;
private LoadingCache<String, Integer> attemptsCache;
public DoorServiceEjb() {
super();
attemptsCache = CacheBuilder
.newBuilder()
.expireAfterWrite(EXPIRY_PERIOD, TimeUnit.MINUTES)
.build(new CacheLoader<String, Integer>() {
#Override
public Integer load(String key) throws Exception {
return 0;
}
}
);
}
public boolean isLockedOut(String key) {
try {
boolean returnValue = attemptsCache.get(key) >= MAX_ATTEMPTS;
return returnValue;
}catch (ExecutionException e) {
return false;
}
}
}
public class Door {
#EJB(beanName = "DoorServiceEjb")
private DoorServiceEjb doorServiceEjb;
public void unlock(String user) {
if (doorServiceEjb.isLockedOut(user)) {
throw new RuntimeException("Locked");
}
// Do something else
}
}
I am expecting that unlock() method to throw RuntimeException if user attempts to call it with invalid username 3 or more times.
MY QUESTIONABLE SOLUTION
Here is my solution to test but I am not sure if this is correct. I was always under impression that asserts and verifications are called always against #InjectMock objects (called subject under test) whereas #Mock objects are just used to mock internal dependencies inside #InjectMock object (basically, they are used to help test setup and run).
My solution, on the contrary, does not use #InjectMock at all and does verify and assert against #Mock object.
And finally, it still fails because last assert fails.
#ExtendWith(MockitoExtension.class)
public class DoorTest {
#Mock
private Door door;
#Test
public void test_3FailedUnlockAttempts_ShouldLock() {
Mockito.doNothing().doNothing().doThrow(RuntimeException.class).when(door).unlock(anyString());
door.unlock(anyString());
door.unlock(anyString());
RuntimeException exception = assertThrows(RuntimeException.class, () -> {
door.unlock(anyString()); // should throw RuntimeException
});
Mockito.verify(door, times(3)).unlock(anyString());
//this fails, the exception message is null rather than "Unlocked"
Assertions.assertTrue(exception.getMessage().contains("Locked"));
}
}

Junit test case for PreparedStatementCallback coverage

#Transactional
public Boolean save(final StudentLogEntry studentLogEntry) throws SQLException,DaoException{
boolean returnFlag = true;
String sqlInsert = "insert into STUDENT_DETAILS (INSERT_DATE,STUDENT_NAME,STUDENT_ID) values(SYSDATE,?,?)";
returnFlag = jdbcTemplate.execute(
sqlInsert,
new PreparedStatementCallback<Boolean>() {
Boolean b=false;
#Override
public Boolean doInPreparedStatement(PreparedStatement pst) {
try {
pst.setString(2, studentLogEntry.getStuName());
pst.setString(3, studentLogEntry.getStuId());
b=pst.execute();
} catch (SQLException e) {
clicklogger.info("SQLException has occurred while inserting studentlog ",e);
} catch (DataAccessException e) {
clicklogger.info("DataAccessException has occurred while inserting studentlog ",e);
}
return b;
}
}
);
return returnFlag;
}
I am using Spring framework for my project, I have written Junit test case for the above code. But I am not able to cover the PreparedStatementCallback. My test case is as below:
#Test
public void testSave() throws DaoException, SQLException {
studentDao.setJdbcTemplate(jdbcTemplate);
studentDao.setTransactionManager(transactionManager);
StudentLogEntry studentLogEntry = new StudentLogEntry();
studentLogEntry.getStuName("ABC");
studentLogEntry.getStuId("1234");
assertEquals("true",studentDao.save(studentLogEntry));
}
The method is doing to much to make it easily and clearly testable.
1) I would move the new PreparedStatementCallback to a specialized class:
public class MyPreparedStatementCallback implements PreparedStatementCallback<Boolean>{
#Override
public Boolean doInPreparedStatement(PreparedStatement pst) {
....
}
I would test the doInPreparedStatement method in separation here. It should not be related to the former test at all.
2) Use the new class in the original method and test whether proper instance has been passed (you would need Mockito here):
returnFlag = jdbcTemplate.execute(sqlInsert,new MyPreparedStatementCallback());
and the test:
#InjectMocks
StudentDao studentDao;
#Mock
JdbcTemplate jdbcTemplateMock;
#Captor
ArgumentCaptor argCaptor;
#Before
public void init(){
MockitoAnnotations.initMocks(this);
}
#Test
public void shouldSaveWithCallback(){
// Act
// set up
studentDao.save(studentLogEntry);
myClass.userPressedButton();
Mockito.verify(jdbcTemplateMock).execute(Mockito.anyString(), argCaptor.capture());
// Assert
assertTrue(argCaptor.getValue() instance of MyPreparedStatementCallback);
}
The bottom line is that you should not test the implementation of that callback withing your original test method. That is too much and your test would be to coarse and hard to maintain.

Java mock a method of a private field that returns null

I am trying to mock a method of a private field that has a return type of void. In my test, I am trying to mock aClass.doSomething() to throw an IllegalStateException and I need to verify that recover() is called. Here is an example:
public class ClassToTest implements Runnable {
private ClassToMock aClass;
#Override
public void run() {
try{
aClass.doSomething("some parameter");
} catch(IllegalStateException e) {
logger.error("Something bad happened", e);
recover();
}
}
public void recover(){
logger.info("I am recovering");
}
}
I have done each piece separately:
Mock a method call of a private field
Mock a method that has void return type
Throw exception
Verify a private method call
but I wasn't able to put all together. Any help is appreciated
I thought I'd elaborate GhostCat's comments:
Stay with Mockito
Mockito is more than a mocking framework - it's a discipline. If you read carefully the documentation for Mockito and restrain yourself from resorting to PowerMock et al you will learn good OOP practice.
Read how to do dependency injection with constructors
Primum non nocere - first refactor your code like this:
public class ClassToTest implements Runnable {
private final ClassToMock aClass;
private final Logger logger;
//injection of collaborators through the constructor
public ClassToTest(ClassToMock aClass, Logger logger) {
this.aClass = aClass;
this.logger = logger;
}
#Override
public void run() {
try{
aClass.doSomething("some parameter");
} catch(IllegalStateException e) {
logger.error("Something bad happened", e);
recover();
}
}
public void recover() { //there is no need for this method to be public - see Effective Java item 13
logger.info("I am recovering");
}
}
Now your code is testable using Mockito without resorting to more complex mocking frameworks:
//mocks
#Mock ClassToMock classToMock;
#Mock Logger mockLogger;
//system under test
ClassToTest classToTest;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks();
classToTest = new ClassToTest(classToMock, mockLogger);
}
#Test
public void whenRun_thenDoesSomethingWithSomeParameter() {
//act
classToTest.run();
//assert
verify(classToMock).doSomething(eq("some parameter"));
}
#Test
public void givenAnIllegalStateForAClass_whenRun_thenLogsError() {
//arrange
IllegalStateException e = new IllegalStateException();
when(classToMock.doSomething(anyString()).thenThrow(e);
//act
classToTest.run();
//assert
verify(mockLogger).error(eq("Something bad happened"), same(e));
}
#Test
public void givenAnIllegalStateForAClass_whenRun_thenLogsRecovery() {
//arrange
when(classToMock.doSomething(anyString()).thenThrow(new IllegalStateException());
//act
classToTest.run();
//assert
verify(mockLogger).info(eq("I am recovering"));
}

Using jmockit to mock constructor that throws error: NoClassDefFoundError

Jmockit is very powerful, but sometimes I cannot understand what it does behind the scene, so I have a question regarding jmockit. Hopefully the more experienced programmers on here could help shine some light on this situation :)
I have the following two classes in two separate files:
public class SmallClass {
String a;
SmallClass(String arg) throws Exception {
a = arg;
}
public String getString() {
return a;
}
}
And
public class BigClass {
private static final SmallClass smallClass;
static {
try {
smallClass = new SmallClass("dummy");
} catch (Exception e) {
throw new IllegalStateException("Could not initialized", e);
}
}
public static String getString() {
return smallClass.getString();
}
}
Now, I have a class to test BigClass:
public class BigClassTest {
#Test
public void testGet() throws Exception {
///CLOVER:OFF
new MockUp<SmallClass>() {
#Mock
public void $init(String string) throws Exception {
//Do nothing
}
#Mock
public String getString() {
return "dummyString";
}
};
///CLOVER:ON
Assert.assertEquals("dummyString", BigClass.getString());
}
#Test(expected = ExceptionInInitializerError.class)
public void testException() throws Exception {
///CLOVER:OFF
new MockUp<SmallClass>() {
#Mock
public void $init(String string) throws Exception{
throw new Exception("Mocked Exception");
}
};
///CLOVER:ON
BigClass.getString();
}
}
If I run each of these independently, then they each passes. But if I run the whole test file, then the first test fails with:
java.lang.NoClassDefFoundError: Could not initialize class BigClass
I also tried tearing down the mock after each test like this, but it doesn't help:
public class BigClassTest {
MockUp<SmallClass> smallClassMockUp;
#Test
public void testGet() throws Exception {
///CLOVER:OFF
smallClassMockUp = new MockUp<SmallClass>() {
#Mock
public void $init(String string) throws Exception {
//Do nothing
}
#Mock
public String getString() {
return "dummyString";
}
};
///CLOVER:ON
Assert.assertEquals("dummyString", BigClass.getString());
smallClassMockUp.tearDown();
}
#Test(expected = ExceptionInInitializerError.class)
public void testException() throws Exception {
///CLOVER:OFF
smallClassMockUp = new MockUp<SmallClass>() {
#Mock
public void $init(String string) throws Exception{
throw new Exception("Mocked Exception");
}
};
///CLOVER:ON
BigClass.getString();
smallClassMockUp.tearDown();
}
}
Any help would be appreciated. Thank you in advance!
The occurrence of NoClassDefFoundError, in a case like this, is not because the class wasn't found by the JVM (it was), but because its static initialization has failed (by throwing an exception or error from the execution of a static initializer). Once this happens, the class is left in an invalid/uninitialized state and cannot be used in the same JVM instance anymore.
For reference, see the "Initialization of classes and interfaces" section in the JLS.
Also, note that the order in which tests execute is not necessarily the textual order they appear in the test class. Here, testException (the second test) runs first. So, when testGet runs, the class is invalid and the JVM throws the error.

Mocking chained methods calls using PowerMock

I have a class which I would like to test with a public static method that contains some chained method calls. Assuming that an exception occurs during the chained method calls, how do I handle this effectively and make it return some specific value?
Following is the code sample of the test class.
#RunWith(PowerMockRunner.class)
#PrepareForTest({CodeWithPrivateMethod.class,CodeWithAnotherPrivateMethod.class,CodeWithYetAnotherPrivateMethod.class})
public class CodeWithPrivateMethodTest {
#Test
public void when_gambling_is_true_then_always_explode() throws Exception {
CodeWithYetAnotherPrivateMethod codeWithYetAnotherPrivateMethod = PowerMockito.spy(new CodeWithYetAnotherPrivateMethod());
PowerMockito.whenNew(CodeWithYetAnotherPrivateMethod.class).withAnyArguments().thenReturn(codeWithYetAnotherPrivateMethod);
CodeWithAnotherPrivateMethod codeWithAnotherPrivateMethod = PowerMockito.spy(new CodeWithAnotherPrivateMethod());
PowerMockito.whenNew(CodeWithAnotherPrivateMethod.class).withAnyArguments().thenReturn(codeWithAnotherPrivateMethod);
PowerMockito.doReturn(true).when(codeWithYetAnotherPrivateMethod, "getGambling");
//PowerMockito.doReturn(codeWithYetAnotherPrivateMethod).when(codeWithAnotherPrivateMethod, "getGambleValue");
PowerMockito.spy(CodeWithPrivateMethod.class);
CodeWithPrivateMethod.startGamble();
}
}
Following is the code sample for the class under test
public class CodeWithPrivateMethod {
public static void startGamble() {
Boolean gamble = CodeWithAnotherPrivateMethod.getGambleValue()
.getGambling();
if (gamble) {
System.out.println("kaboom");
}else{
System.out.println("boom boom");
}
}
}
Following is the code sample for the class that gets called from the class under test
public class CodeWithAnotherPrivateMethod {
static CodeWithYetAnotherPrivateMethod codeWithYetAnotherPrivateMethod = new CodeWithYetAnotherPrivateMethod();
public static CodeWithYetAnotherPrivateMethod getGambleValue() {
return codeWithYetAnotherPrivateMethod; //works fine
return null; // fails
}
}
Following is the code sample for the other class that gets called from the class under test
public class CodeWithYetAnotherPrivateMethod {
public Boolean getGambling() {
return false;
}
}
So Assuming I return a null value from getGambleValue() method of CodeWithAnotherPrivateMethod class, how do I handle this null value effectively in my testclass?
This is how to specify expected exceptions using Mockito:
#Test(expected = NullPointerException.class)
public void when_gambling_is_true_then_always_explode() throws Exception {
...
Before I found out about this I would do:
#Test
public void when_gambling_is_true_then_always_explode() throws Exception {
// setup omitted
try {
CodeWithPrivateMethod.startGamble();
}
catch(NullPointerException e) {
// expected
return;
}
fail("Expected NullPointerException");
}
EDIT: Testing multiple classes that call each other statically like this is a severe code smell. Unit tests should test a single class and inline static calls should be limited to utility classes.
Another comment: your example class names are very confusing. Next time please stick with Foo, Bar, Baz or Appple, Pear, Banana.
If you are not getting an NPE then I expect your mocking/spying is interfering. If you call the code under test without mocking/spying the call chain would be:
CodeWithPrivateMethod.startGamble();
->
CodeWithYetAnotherPrivateMethod value = CodeWithAnotherPrivateMethod.getGambleValue();
->
return null;
<-
value.getGambling();
<- throws NullPointerException
What exactly are you trying to find out or achieve?
EDIT: Here's how it should work with PowerMock
#RunWith(PowerMockRunner.class)
#PrepareForTest(CodeWithAnotherPrivateMethod.class)
public class CodeWithPrivateMethodTest {
#Mock
private CodeWithYetAnotherPrivateMethod yetAnotherInstance;
#Test
public final void testStartGamble() {
// SETUP
mockStatic(CodeWithAnotherPrivateMethod.class);
expect(CodeWithAnotherPrivateMethod.getGambleValue())
.andReturn(yetAnotherInstance);
Boolean gamblingValue = true;
expect(yetAnotherInstance.getGambling()).andReturn(gamblingValue);
replayAll();
// CALL
CodeWithPrivateMethod.startGamble();
// VERIFY
verifyAll();
}

Categories