JUnit – Expected Exceptions Test

In JUnit, there are 3 ways to test the expected exceptions :

  1. @Test, optional ‘expected’ attribute
  2. Try-catch and always fail()
  3. @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 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);

    }

}

References

  1. JUnit Wiki Exception Testing
  2. Java Custom Exception Examples

8 comments on “JUnit – Expected Exceptions Test

  1. 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 ?

    Reply
  2. 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

    Reply
  3. Hi Mkyong – I’m always happy when I run into your tutorials. Thanks for doing this.

    Reply
  4. “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 🙂

    Reply
  5. @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

    Reply

Leave a Comment

Your email address will not be published. Required fields are marked *