可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
This question already has an answer here:
-
In Java how can I validate a thrown exception with JUnit?
10 answers
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.
回答1:
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"));
}
回答2:
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=...)
.
回答3:
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());
}
回答4:
try
{
// your code
fail("Didn't throw expected exception");
}
catch(CriticalServerException e)
{
assertEquals("Expected message", e.getMessage());
}
回答5:
try {
// test code invacation
fail("Exception not throw!!!");
} catch(CriticalServerException ex) {
assertTrue("Invalid exception data", ex.toString().contains("error text"));
}
回答6:
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();
回答7:
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
回答8:
Use catch-exception:
catchException(obj).doSomethingCritical();
assertTrue(caughtException() instanceof CriticalServerException);
assertEquals("Expected Message", caughtException().getMessage());
回答9:
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();
}
回答10:
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.
回答11:
Java 8 solution
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.
}
(taken from my blog)
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