Search code examples
javajunitpowermockito

PowerMockito doThrow not throwing exception


I am attempting to test for a thrown exception but the code continues on to return true instead of catching the exception and returning false.

Test class

@RunWith(PowerMockRunner.class)
@PrepareForTest({Class1.class, Class2.class})
public class TestClass 
{

private Argument arg;
private static Class1 mockObj1;
private static Class2 mockObj2;

@BeforeClass
public static void initialSetup()
{
    PowerMockito.mockStatic(Class1.class);
    mockObj1 = PowerMockito.mock(Class1.class);
    mockObj2 = PowerMockito.mock(Class2.class);
}

@Before
public void setupForEachTest()
{   
    arg = new Argument();
}   

@Test
public void testUpdate() throws RemoteException
{
    PowerMockito.when(Class1.getDefault()).thenReturn(mockObj1);
    PowerMockito.when(mockObj1.getClass2()).thenReturn(mockObj2);
    PowerMockito.doThrow(new RemoteException()).when(mockObj2).save(arg);
    assertFalse(rule.update(null, null, null, null, null, null, null, null, null, null, null));
}

method to be tested

public boolean update(params)
{   
    try
    {           
      Class1.getDefault().getClass2().save(args);
    }

    catch(RemoteException e)
    {
        Log.error(this, e);
        return false;
    }

    return true;
}

I get an assertion error each time I try to run this I have tried both the do throw and thenThrow methods any help with this would be appreciated.

edit:

StackTrace

java.lang.AssertionError: 
    at org.junit.Assert.fail(Assert.java:91)
    at org.junit.Assert.assertTrue(Assert.java:43)
    at org.junit.Assert.assertFalse(Assert.java:68)
    at org.junit.Assert.assertFalse(Assert.java:79)
    at package.TestClass.testUpdate(TestClass.java:92)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:66)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:326)
    at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:86)
    at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:94)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:310)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:131)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.access$100(PowerMockJUnit47RunnerDelegateImpl.java:59)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner$TestExecutorStatement.evaluate(PowerMockJUnit47RunnerDelegateImpl.java:147)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.evaluateStatement(PowerMockJUnit47RunnerDelegateImpl.java:107)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:298)
    at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:84)
    at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:218)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:160)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:134)
    at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34)
    at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44)
    at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:136)
    at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:121)
    at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:57)
    at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:59)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

save method

public abstract int save(Argument paramarg)
throws RemoteException;

Solution

  • I'm still a bit confused by the question. Specifically:

    • The test instances arg = new Argument() in a @Before method which implies that arg is relevant to each test.
    • The provided update() method declaration looks like this: public boolean update(params), it does not define the type for the params argument.
    • The question also provides this implementation for the save() method: int save(Argument paramarg) throws RemoteException; which implies that Argument arg is passed into update() so by extension the type of params must be Argument but the test case calls rule.update(null, null, null, ...)

    Anwyay, given these assumptions:

    • The update() method is:

      public boolean update(Argument params) {
          try {
              Class1.getDefault().getClass2().save(params);
          } catch (RemoteException e) {
              return false;
          }
      
          return true;
      }   
      
    • The save() method is;

      save(Argument arg) throws RemoteException
      

    The following test passes:

    @RunWith(PowerMockRunner.class)
    @PrepareForTest({Class1.class})
    public class ATestClass {
    
        private Argument arg;
        private Class1 mockObj1;
        private Class2 mockObj2;
    
        @Before
        public void initialSetup() {
            PowerMockito.mockStatic(Class1.class);
    
            mockObj1 = Mockito.mock(Class1.class);
    
            mockObj2 = Mockito.mock(Class2.class);
        }
    
        @Before
        public void setupForEachTest() {
            arg = new Argument();
        }
    
        @Test
        public void testUpdate() throws RemoteException {
            PowerMockito.when(Class1.getDefault()).thenReturn(mockObj1);
            Mockito.when(mockObj1.getClass2()).thenReturn(mockObj2);
    
            Mockito.when(mockObj2.save(Mockito.any(Argument.class))).thenThrow(new RemoteException());
    
            Assert.assertFalse(update(arg));
        }
    }
    

    Note: you only need to use PowerMock to take care of this invocation: Class1.getDefault(), all other mocked invocations are neither static nor final so Mockito suffices.