Search code examples
junitpowermock

Test with ExpectedException fails when using PoweMock with PowerMockRule


I am trying to work with PowerMock, over Mockito; as I loved the API's for whennew() and verifyprivate() but i have some problem when trying to run testsuites with Categories TestRunner in Junit.

For using default JUnit test runners, I created a TestCase and added PowerMockRule as instance field with @Rule annotation. While execution of tests worked like this, ExpectedException TestRule is not working when used in conjunction

Example Code

@PowerMockIgnore ("*")
@PrepareForTest (CustomizedSSHConnection.class)
public class TestExpectedExceptionRule {

    private Connection          connection;
    private ConnectionInfo      connectionInfo;
     @Rule
     public PowerMockRule rule = new PowerMockRule ();
    @Rule
    public ExpectedException    exception   = ExpectedException.none ();

    @Test
    public void testExcepitonWithPowerMockRule() {
        exception.expect (NullPointerException.class);
        exception.expectMessage ("Image is null");
        throw new NullPointerException ("Image is null");
    }
}

Instead of using @Rule PowerMockRule if I use @RunWith(PowerMockRunner.class) this testcase will pass.

One other observation is if I annotate PowerMockRule with @ClassRule this succeeds but some of the mocking methods throwing exceptions.


Solution

  • PowerMock creates a deep clone of the TestExpectedExceptionRule object. Because of this it is running the test with a new ExpectedException rule, but you're calling exception.expect (NullPointerException.class) on the original rule. Hence the test fails, because the clone of the ExpectedException rule doesn't expect an exception.

    Nevertheless there are at least two solutions for your problem.

    RuleChain

    Order the rules with JUnit's RuleChain. This needs some additional ugly code, but it works.

    private ExpectedException exception = ExpectedException.none ();
    private PowerMockRule powerMockRule = new PowerMockRule();
    
    @Rule
    public TestRule ruleChain = RuleChain.outerRule(new TestRule() {
        @Override
        public Statement apply(Statement base, Description description) {
            return powerMockRule.apply(base, null, description);
        }
    }).around(exception);
    

    Fishbowl

    If you are using Java 8 then you can replace the ExpectedException rule with the Fishbowl library.

    @Test
    public void testExcepitonWithPowerMockRule() {
      Throwable exception = exceptionThrownBy(
        () -> throw new NullPointerException ("Image is null"));
      assertEquals(NullPointerException.class, exception.getClass());
      assertEquals("Image is null", exception.getMessage());
    }
    

    Without Java 8, you have to use an anonymous class.

    @Test
    public void fooTest() {
      Throwable exception = exceptionThrownBy(new Statement() {
        public void evaluate() throws Throwable {
          throw new NullPointerException ("Image is null");
        }
      });
      assertEquals(NullPointerException.class, exception.getClass());
      assertEquals("Image is null", exception.getMessage());
    }