In JUnit, I'm currently using annotation to expect an exception in my tests.
Is there a way to analyse this exception? For example, I expect a CriticalServerException
, but I also want to verify the content of the getMessage
method.
In JUnit, I'm currently using annotation to expect an exception in my tests.
Is there a way to analyse this exception? For example, I expect a CriticalServerException
, but I also want to verify the content of the getMessage
method.
If you have JUnit 4.7 or above try ExpectedException
There is an example in this question, which is copied below:
@Rule
public ExpectedException exception = ExpectedException.none();
@Test
public void testRodneCisloRok(){
exception.expect(IllegalArgumentException.class);
exception.expectMessage("error1");
new RodneCislo("891415",dopocitej("891415"));
}
I'm not sure if you should. Using a try-catch block to check the error message is so junit3ish. We have this cool feature now that you can write @Test(expected=CriticalServerException.class)
and you want to go "back" and use try-catch again to fetch an exception you expect, just for checking the error message?
IMO you should stay for the @Test(expected=CriticalServerException.class)
annotation and ignore the error message. Checking the error message, which can be changed a lot as it is a more "human readable" string and not a technical value, can also be tricky. You are forcing the exception to have a specific error message, but you might not know who generated the exception and what error message he chose.
In general you want to test if the method throws the exception or not, and not what the actual error message looks like. If the error message is really so important you should maybe consider using a subclass of the exception it throws and check it in @Test(expected=...)
.
try{
//your code expecting to throw an exception
fail("Failed to assert :No exception thrown");
} catch(CriticalServerException ex){
assertNotNull("Failed to assert", ex.getMessage())
assertEquals("Failed to assert", "Expected Message", ex.getMessage());
}
try
{
// your code
fail("Didn't throw expected exception");
}
catch(CriticalServerException e)
{
assertEquals("Expected message", e.getMessage());
}
try {
// test code invacation
fail("Exception not throw!!!");
} catch(CriticalServerException ex) {
assertTrue("Invalid exception data", ex.toString().contains("error text"));
}
Use MethodRule as a common solution, if you have many test cases to test
public class ExceptionRule implements MethodRule {
@Override
public Statement apply(final Statement base, final FrameworkMethod method, Object target) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
try {
base.evaluate();
Assert.fail();
} catch (CriticalServerException e) {
//Analyze the exception here
}
}
};
}
}
Then use the Rule to your test class:
@Rule public ExceptionRule rule = new ExceptionRule();
I don't think there is a way of doing it using annotation. You may have to fall back to try-catch way where in the catch block you can verify the message
Use catch-exception:
catchException(obj).doSomethingCritical();
assertTrue(caughtException() instanceof CriticalServerException);
assertEquals("Expected Message", caughtException().getMessage());
Look at fluent-exception-rule, it "combines Junit ExpectedException rule and AssertJ's assertions convenience. "
import pl.wkr.fluentrule.api.FluentExpectedException;
...
@Rule
public FluentExpectedException thrown = FluentExpectedException.none();
@Test
public void testDoSomethingCritical() {
thrown.expect(CriticalServerException.class).hasMessage("Expected Message").hasNoCause();
obj.doSomethingCritical();
}
If you want to compare message along with exception type then you can try below code snippet.
@Rule
public ExpectedException expectedException = ExpectedException.none();
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Parameter is not valid"); //check string contains
expectedException.expectMessage(CoreMatchers.equalTo("Parameter is not valid")); //check string equals
Note: This will work for junit 4.9 onward.
Here is a utility function that I wrote:
public final <T extends Throwable> T expectException( Class<T> exceptionClass, Runnable runnable )
{
try
{
runnable.run();
}
catch( Throwable throwable )
{
if( throwable instanceof AssertionError && throwable.getCause() != null )
throwable = throwable.getCause(); //allows "assert x != null : new IllegalArgumentException();"
assert exceptionClass.isInstance( throwable ) : throwable; //exception of the wrong kind was thrown.
assert throwable.getClass() == exceptionClass : throwable; //exception thrown was a subclass, but not the exact class, expected.
@SuppressWarnings( "unchecked" )
T result = (T)throwable;
return result;
}
assert false; //expected exception was not thrown.
return null; //to keep the compiler happy.
}
Use it as follows:
@Test
public void testThrows()
{
RuntimeException e = expectException( RuntimeException.class, () ->
{
throw new RuntimeException( "fail!" );
} );
assert e.getMessage().equals( "fail!" );
}
Also, if you would like to read some reasons why you should not want to check the message of your exception, see this: https://softwareengineering.stackexchange.com/a/278958/41811