JUnit – Expected Exceptions Test
In JUnit, there are 3 ways to test the expected exceptions :
@Test
, optional ‘expected’ attribute- Try-catch and always
fail()
@Rule
ExpectedException
P.S Tested with JUnit 4.12
1. @Test expected attribute
Use this if you only want to test the exception type, refer below :
Exception1Test.java
package com.mkyong;
import org.junit.Test;
import java.util.ArrayList;
public class Exception1Test {
@Test(expected = ArithmeticException.class)
public void testDivisionWithException() {
int i = 1 / 0;
}
@Test(expected = IndexOutOfBoundsException.class)
public void testEmptyList() {
new ArrayList<>().get(0);
}
}
2. Try-catch and always fail()
This is a bit old school, widely used in JUnit 3. Test the exception type and also the exception detail. Refer below :
Exception2Test.java
package com.mkyong;
import org.junit.Test;
import java.util.ArrayList;
import static junit.framework.TestCase.fail;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
public class Exception2Test {
@Test
public void testDivisionWithException() {
try {
int i = 1 / 0;
fail(); //remember this line, else 'may' false positive
} catch (ArithmeticException e) {
assertThat(e.getMessage(), is("/ by zero"));
//assert others
}
}
@Test
public void testEmptyList() {
try {
new ArrayList<>().get(0);
fail();
} catch (IndexOutOfBoundsException e) {
assertThat(e.getMessage(), is("Index: 0, Size: 0"));
}
}
}
Always remember the fail()!
If the line you want to test didn’t throw any exception, and you forgot to put the
If the line you want to test didn’t throw any exception, and you forgot to put the
fail()
, the test will be passed (false positive).
3. @Rule ExpectedException
This ExpectedException
rule (since JUnit 4.7) let you test both the exception type and also the exception detail, same like “2. Try-catch and always fail()” method, but in a more elegant way :
Exception3Test.java
package com.mkyong;
import com.mkyong.examples.CustomerService;
import com.mkyong.examples.exception.NameNotFoundException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.hasProperty;
public class Exception3Test {
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void testDivisionWithException() {
thrown.expect(ArithmeticException.class);
thrown.expectMessage(containsString("/ by zero"));
int i = 1 / 0;
}
@Test
public void testNameNotFoundException() throws NameNotFoundException {
//test type
thrown.expect(NameNotFoundException.class);
//test message
thrown.expectMessage(is("Name is empty!"));
//test detail
thrown.expect(hasProperty("errCode")); //make sure getters n setters are defined.
thrown.expect(hasProperty("errCode", is(666)));
CustomerService cust = new CustomerService();
cust.findByName("");
}
}
NameNotFoundException.java
package com.mkyong.examples.exception;
public class NameNotFoundException extends Exception {
private int errCode;
public NameNotFoundException(int errCode, String message) {
super(message);
this.errCode = errCode;
}
public int getErrCode() {
return errCode;
}
public void setErrCode(int errCode) {
this.errCode = errCode;
}
}
CustomerService.java
package com.mkyong.examples;
import com.mkyong.examples.exception.NameNotFoundException;
public class CustomerService {
public Customer findByName(String name) throws NameNotFoundException {
if ("".equals(name)) {
throw new NameNotFoundException(666, "Name is empty!");
}
return new Customer(name);
}
}
Hi Mkyong – I’m always happy when I run into your tutorials. Thanks for doing this.
When we use ExceptionRule, and the exception object being thrown has some custom attribute which contains the message (i.e not the getMessage method), how such custom field value/message can be asserted ?
I have a method callFile as following in my code, I want to test it using junit. Can anyone help me in writing the test case
public String callFile(String myFile) {
System.out.println(“Requested File:” + myFile);
StringBuilder stringJson = new StringBuilder();
try {
FileReader logReader = new FileReader(myFile);
BufferedReader buffer = new BufferedReader(logReader);
if (buffer != null) {
int cp;
while ((cp = buffer.read()) != -1) {
stringJson.append((char) cp);
}
buffer.close();
}
}
catch (Exception e) {
throw new RuntimeException(
“Exception while reading File:” + myFile, e);
}
return stringJson.toString();
}
Thanks
“In above example, the divisionWithException() method will throw an ArithmeticException Exception, since this is an expected exception, so the unit test will pass.”
Too much ex-s in a sentence. But thanks a lot for your tutorials 🙂
@RunWith(value = Parameterized.class)
public class JunitTest8A {
private TestUDC udc1 , udc2;
public JunitTest8A(String name, int count) {
this.udc1 = new TestUDC(name,count) ;
}
@Parameters
public static Collection data() {
Object[][] data = new Object[][] { { “1”,2 }, {“3”,4 }, {“5”,6}, {“7”,8 } };
return Arrays.asList(data);
}
@Test
public void pushTest() {
System.out.println(“Parameterized UDC is : ” + udc1.getName()+ ” Number2 is : ” + udc1.getCount());
}
}
public class TestUDC
{
public TestUDC(String name, int count)
{
this.name = name;
this.count = count ;
}
private String name;
private int count;
String getName() { return name ; }
int getCount() { return count ; }
}
Hi I enjoyed learning from your tutorials. Please consider including the above example.
I would also include dependency junit-4.4.jar and compilation and run steps.
to Compile
javac -classpath junit-4.4.jar;. java-file
to run
java -cp junit-4.4.jar;. org.junit.runner.JUnitCore java-class-name
As above, I extended it to take multiple parameters String and int.
I tried extending to user defined class as follows
public class TestUDC
{
public TestUDC(String name, int count)
{
this.name = name;
this.count = count ;
}
private String name;
private int count;
String getName() { return name ; }
int getCount() { return count ; }
}
import java.util.Arrays;
import java.util.Collection;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
/**
* JUnit Parameterized Test
* @author mkyong extended by Raman Kannan
*
*/
@RunWith(value = Parameterized.class)
public class JunitTest8 {
private TestUDC udc1 , udc2;
public JunitTest8(TestUDC udc) {
this.udc1 = udc1 ;
}
@Parameters
public static Collection data() {
Object[][] data = new Object[][] { { new TestUDC(“1”,2) }, {new TestUDC(“3”,4) }, { new TestUDC(“5”,6 )}, {new TestUDC(“7”,8) } };
return Arrays.asList(data);
}
@Test
public void pushTest() {
System.out.println(“Parameterized UDC is : ” + udc1.getName()+ ” Number2 is : ” + udc1.getCount());
}
}
This does not appear to run..compiles ok but does not run..throws some exception.
thanks
vf
Very nice tutorials! Thanks a lot!
nice blog! thanks for the help.
share link to download examples in each tutorial