I have a problem with ExpectedException. I'm using it in many tests in one test class. Now i got the problem that our Jenkins has one failing test because this test has the expectedMessage of a previous test. I have no idea why but to prevent this fail i tried to "clear" the ExpectedMessage but it does not behave like expected:
TestClass
public class TestClass {
#Rule
public ExpectedException expectedException = ExpectedException.none();
#Test
public void testExpectedException() throws Exception {
//old expectation
expectedException.expect(Exception.class);
expectedException.expectMessage("something");
//try to reset
expectedException = ExpectedException.none();
//new expectation
expectedException.expect(Exception.class);
expectedException.expectMessage("random");
Thrower exe = new Thrower();
exe.testedMethod();
}
}
Thrower
public class Thrower {
public void testedMethod() throws Exception {
throw new Exception("random");
}
}
The testExpectedException leads to the following output:
java.lang.AssertionError:
Expected: (an instance of java.lang.Exception and exception with message a string containing "something")
but: exception with message a string containing "something" message was "random"
Stacktrace was: java.lang.Exception: random
But i would expect that expectedException checks for a message containing random. Why does it not?
I am using JUnit 4.11.
Related
I have this Junit test in my project
public class CalculatorBookingTest {
private CalculatorBooking calculatorBooking;
#Rule
public ExpectedException expectedException = ExpectedException.none();
#Before
public void setUp() {
calculatorBooking = new CalculatorBooking();
}
#Test
public void shouldThrowAnException_When_InputIsNull() {
calculatorBooking.calculate(null, null, 0, null);
expectedException.expect(CalculationEngineException.class);
expectedException.expectMessage("Error");
}
}
but when I run the test, the Exception is Thrown but nevertheless the test fail
You could do something like:
#Test(expected = CalculationEngineException.class)
public void shouldThrowAnException_When_InputIsNull() {
calculatorBooking.calculate(null, null, 0, null);
}
From Junit doc :
The Test annotation supports two optional parameters. The first,
expected, declares that a test method should throw an exception. If it
doesn't throw an exception or if it throws a different exception than
the one declared, the test fails.
You need to first tell JUnit that the method is expected to throw the exception. Then when it's thrown - it knows that the test passes. In your code you put expect() after the exception is thrown - so the execution doesn't even go that far. The right way:
#Test
public void shouldThrowAnException_When_InputIsNull() {
expectedException.expect(CalculationEngineException.class);
expectedException.expectMessage("Error");
calculatorBooking.calculate(null, null, 0, null);
}
Place expectedException.expect before the call that will throw the exception.
#Test
public void shouldThrowAnException_When_InputIsNull() {
expectedException.expect(CalculationEngineException.class);
expectedException.expectMessage("Error");
calculatorBooking.calculate(null, null, 0, null);
}
I am writing JUnit4 unit tests and have a condition where I need to assert that an exception was thrown with null message.
#Rule
public final ExpectedException exception = ExpectedException.none();
#Test
public final void testNullException() throws Exception {
exception.expect(Exception.class);
exception.expectMessage((String) null);
mPackage.getInfo(null);
}
The line mPackage.getInfo(null) is throwing an Exception with null message properly, but the JUnit test is failing with the message:
java.lang.AssertionError:
Expected: (an instance of java.lang.Exception and exception with message a string containing null)
but: exception with message a string containing null message was null
Is there anyway to test for an exception with a null message in JUnit4 way. (I know I can catch the exception and check for the conditions myself).
Using org.hamcrest.Matcher with org.hamcrest.core.IsNull worked for me.
The syntax is,
#Rule
public final ExpectedException exception = ExpectedException.none();
#Test
public final void testNullException() throws Exception {
exception.expect(Exception.class);
Matcher<String> nullMatcher = new IsNull<>();
exception.expectMessage(nullMatcher);
mPackage.getInfo(null);
}
Could you tell me please, is it normal practice to write a method (example: JUnit Test) that throws an Exception, for example:
class A {
public String f(int param) throws Exception {
if (param == 100500)
throw new Exception();
return "";
}
}
private A object = new A();
#Test
public void testSomething() throws Exception {
String expected = "";
assertEquals(object.f(5), expected);
}
In fact, method f() won't throw an exception for that parameter(5) but nevertheless I must declare that exception.
Yes it is completely fine, and if it does throw the exception the test will be considered as failed.
You need to specify that the method throws an Exception even if you know that the specific case does not (this check is done by the compiler).
In this case, what you expect is object.f(5) returns an empty string. Any other outcome (non-empty string or throwing an exception) would result in a failed test case.
A JUnit-Test is meant to test a given method for correct behavior. It is a perfectly valid scenario that the tested method throws an error (e.g. on wrong parameters). If it is a checked exception, you either have to add it to your test method declaration or catch it in the method and Assert to false (if the exception should not occur).
You can use the expected field in the #Test annotation, to tell JUnit that this test should pass if the exception occurs.
#Test(expected = Exception.class)
public void testSomething() throws Exception {
String expected = "";
assertEquals(object.f(5), expected);
}
In this case, the tested method should throw an exception, so the test will pass. If you remove the expected = Exception.class from the annotation, the test will fail if an exception occurs.
If the method you're calling throws a checked exception yes, you'll either need a try catch or to rethrow. It's fine to do this from the test itself. There are a variety of ways to test Exception using JUnit. I've tried to provide a brief summary below:
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
/**
* Example uses Kent Beck - Test Driven Development style test naming
* conventions
*/
public class StackOverflowExample {
#Rule
public ExpectedException expectedException = ExpectedException.none();
#Test
// Note the checked exception makes us re-throw or try / catch (we're
// re-throwing in this case)
public void calling_a_method_which_throws_a_checked_exception_which_wont_be_thrown() throws Exception {
throwCheckedException(false);
}
/*
* Put the class of the specific Exception you're looking to trigger in the
* annotation below. Note the test would fail if it weren't for the expected
* annotation.
*/
#Test(expected = Exception.class)
public void calling_a_method_which_throws_a_checked_exception_which_will_be_thrown_and_asserting_the_type()
throws Exception {
throwCheckedException(true);
}
/*
* Using ExpectedException we can also test for the message. This is my
* preferred method.
*/
#Test
public void calling_a_method_which_throws_a_checked_exception_which_will_be_thrown_and_asserting_the_type_and_message()
throws Exception {
expectedException.expect(Exception.class);
expectedException.expectMessage("Stack overflow example: checkedExceptionThrower");
throwCheckedException(true);
}
// Note we don't need to rethrow, or try / catch as the Exception is
// unchecked.
#Test
public void calling_a_method_which_throws_an_unchecked_exception() {
expectedException.expect(Exception.class);
expectedException.expectMessage("Stack overflow example: uncheckedExceptionThrower");
throwUncheckedException();
}
private void throwCheckedException(boolean willThrow) throws Exception {
// Exception is a checked Exception
if (willThrow) {
throw new Exception("Stack overflow example: checkedExceptionThrower");
}
}
private void throwUncheckedException() throws NullPointerException {
// NullPointerException is an unchecked Exception
throw new NullPointerException("Stack overflow example: uncheckedExceptionThrower");
}
}
You can test that the exception is launched with this:
#Test(expected = ValidationException.class)
public void testGreaterEqual() throws ValidationException {
Validate.greaterEqual(new Float(-5), 0f, "error7");
}
Suppose that I have a class like;
public class FooBar {
public int getMethod(List<String> code){
if(code.size() > 100)
throw new Exception;
return 0;
}
}
and I have a test class like this;
#RunWith(PowerMockRunner.class)
#PrepareForTest(FooBar.class)
public class FooBarTest{
FooBar fooBarInstance;
#Before
public void setUp() {
//MockitoAnnotations.initMocks(this);
fooBarInstance = new FooBar();
}
#Test(expected = Exception.class)
public void testGetCorrelationListCodesParameter() {
List<String> codes = Mockito.spy(new ArrayList<String>());
Mockito.doReturn(150).when(codes).size();
fooBarInstance.getMethod(codes);
}
}
How can I make this test method to throw an exception ? I've dealing for hours to do this. Well thanks anyway.
Spying is not needed, mocking is enough. As #David said, also mocking is not needed and not recommended for value object.
Using #Test(expected = Exception.class) has many drawbacks, test can pass when exception is thrown from not expected places. Test is not working but is visible as green.
I prefer BDD style testing with catch-exception.
Reasons for using catch-exceptions
(...) in comparison to the use of try/catch blocks.
The test is more concise and easier to read.
The test cannot be corrupted by a missing assertion. Assume you forgot to type fail() behind the method call that is expected to throw an exception.
(...) in comparison to test runner-specific mechanisms that catch and verify exceptions.
A single test can verify more than one thrown exception.
The test can verify the properties of the thrown exception after the exception is caught.
The test can specify by which method call the exception must be thrown.
The test does not depend on a specific test runner (JUnit4, TestNG).
import static com.googlecode.catchexception.CatchException.caughtException;
import static com.googlecode.catchexception.apis.CatchExceptionAssertJ.*;
public class FooBarTest {
FooBar sut = new FooBar(); // System Under Test
#Test
public void shouldThrowExceptionWhenListHasTooManyElements() {
when(sut).getMethod(listWithSize(150));
then(caughtException()).isInstanceOf(Exception.class);
}
private List<String> listWithSize(int size) {
return new ArrayList<String>(Arrays.asList(new String[size]));
}
}
Full working code for this test: https://gist.github.com/mariuszs/8543918
Not recommended solution with expected and mocking.
#RunWith(MockitoJUnitRunner.class)
public class FooBarTest {
#Mock
List<String> codes;
FooBar fooBarInstance = new FooBar();
#Test(expected = Exception.class)
public void shouldThrowExceptionWhenListHasTooManyElements() throws Exception {
when(codes.size()).thenReturn(150);
fooBarInstance.getMethod(codes);
}
}
A list is a value object. It's not something we should mock. You can write this whole test without mocking anything, if you're prepared to build a list that has a size in excess of 100.
Also, I prefer to use JUnit's ExpectedException mechanism, because it lets you check which line of the test method threw the exception. This is better than passing an argument to the #Test annotation, which only lets you check that the exception was thrown somewhere within the method.
public class FooBarTest {
#Rule
public ExpectedException exceptionRule = ExpectedException.none();
private FooBar toTest = new FooBar();
#Test
public void getMethodThrowsException_whenListHasTooManyElements() {
List<String> listWith101Elements =
new ArrayList<String>(Arrays.asList(new String[101]));
exceptionRule.expect(Exception.class);
toTest.getMethod(listWith101Elements);
}
}
In JUnit 4 you can declare expected exception using #Test(expected = SomeException.class) annotation. However, when testing is done using Theories, #Theory annotation does not have expected property.
What is the best way to declare expected exception when testing Theories?
I prefer using ExpectedException rule:
import org.junit.rules.ExpectedException;
<...>
#Rule
public ExpectedException thrown = ExpectedException.none();
#Theory
public void throwExceptionIfArgumentIsIllegal(Type type) throws Exception {
assumeThat(type, equalTo(ILLEGAL));
thrown.expect(IllegalArgumentException.class);
//perform actions
}
Also you can use a normal assert. You can use it on older versions of JUnit (before 4.9).
#Test
public void exceptionShouldIncludeAClearMessage() throws InvalidYearException {
try {
taxCalculator.calculateIncomeTax(50000, 2100);
fail("calculateIncomeTax() should have thrown an exception.");
} catch (InvalidYearException expected) {
assertEquals(expected.getMessage(),
"No tax calculations available yet for the year 2100");
}
}