Reputation: 497
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.
Upvotes: 1
Views: 5899
Reputation: 128
I solved this problem by creating a PowerMockTestUtil
class that uses a FunctionalInterface
.
Utility class:
/**
* Utility class to provide some testing functionality that doesn't play well with Powermock out
* of the box. For example, @Rule doesn't work well with Powermock.
*/
public class PowerMockTestUtil {
public static void expectException(RunnableWithExceptions function, Class expectedClass, String expectedMessage) {
try {
function.run();
fail("Test did not generate expected exception of type " + expectedClass.getSimpleName());
} catch (Exception e) {
assertTrue(e.getClass().isAssignableFrom(expectedClass));
assertEquals(expectedMessage, e.getMessage());
}
}
@FunctionalInterface
public interface RunnableWithExceptions<E extends Exception> {
void run() throws E;
}
}
Sample test:
@Test
public void testValidateMissingQuantityForNewItem() throws Exception {
...
expectException(() -> catalogEntryAssociationImporter.validate(line),
ImportValidationException.class,
"Quantity is required for new associations");
}
Upvotes: 0
Reputation: 497
I was able to fix this using the expected attribute in the @Test
annotation. But the problem with this approach is that am unable to assert the exception message. Which is fine for me for now.
@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(expected = NullPointerException.class)
public void testExcepitonWithPowerMockRule() {
throw new NullPointerException ("Image is null");
}
}
Upvotes: 0
Reputation: 24540
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.
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);
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());
}
Upvotes: 2