简体   繁体   中英

Java - How to Test Catch Block?

Bit of a repost, but a certain catch-22 about not having enough reputation means I can't comment on any of the duplicate threads! (cough cough)

I'm trying to test the catch block of a try-catch using Mockito; is it possible to make a mock throw an exception that is handled by the method being tested? I can't use doThrow()...when()... or @Test(expected = Foo.class) because the exception is handled. I want to test that the method handles Exceptions properly.

@Controller
public class StockExchangeController {

    public ModelAndView placeOrder(ModelAndView mav, MyObj myObj) {

        try {
            validator.validate(myObj); // Throws CustomException if validation fails
            mav.setViewName("successPage");

        } catch (CustomException ex) {
            mav.setViewName("failPage");
        }

        return mav;
    }
}

I'd like to be able to stub the behaviour of my "validatorObject", like

doThrow(new CustomException()).when(validatorMock).validate();

Is there a way to do this?

The answer here (Test catch block logic with Junit and mockito) doesn't work (I believe) because the exception is handled before it gets to test level.

Tips and thoughts much appreciated!

BDD Style Solution

Mockito alone is not the best solution for handling exceptions, use Mockito with Catch-Exception

Mockito + Catch-Exception + AssertJ
given(otherServiceMock.bar()).willThrow(new MyException());

when(myService).foo();

then(caughtException()).isInstanceOf(MyException.class);
Sample code Dependencies
  • eu.codearte.catch-exception:catch-exception:1.3.3
  • org.assertj:assertj-core:1.7.0
Disadvantage
  • Only Mockito up to 1.10.8 is supported

Why should doThrow(..).when(..)... not work?

The placeOrder method catches the exception and returns a testable result:

@RunWith(MockitoJUnitRunner.class)
public class TestStockExchangeController {

    @Mock
    Validator validator;

    @Mock MyObj myObj;

    @Test
    public void testException() throws CustomException {
        StockExchangeController sec = new StockExchangeController(validator);
        doThrow(new CustomException()).when(validator).validate(myObj);

        ModelAndView modelAndView = sec.placeOrder(new ModelAndView(), myObj);
        assertEquals("failPage", modelAndView.getViewName());
    }
}

I've tested with these two files:

Main source code:

//src/main/java/StockExchangeController.java
public class StockExchangeController {

    private ValidationFactory factory;

    public ModelAndView placeOrder(ModelAndView mav, MyObj myObj) {
        Validator validator = factory.getValidator("S");
        try {
            validator.validate(myObj); // Throws CustomException if validation fails
            mav.setViewName("successPage");
        } catch (CustomException ex) {
            mav.setViewName("failPage");
        }
        return mav;
    }
}

class CustomException extends Exception {}

interface ValidationFactory {
    Validator getValidator(String s);
}

class Validator {
    public void validate(MyObj myObj) throws CustomException {}
}

class ModelAndView {
    private String viewName;

    public void setViewName(String viewName) {
        this.viewName = viewName;
    }

    public String getViewName() {
        return viewName;
    }
}

class MyObj {}

Test source code:

//src/test/java/TestStockExchangeController.java
//various imports
@RunWith(MockitoJUnitRunner.class)
public class TestStockExchangeController {

    @Mock
    private Validator validator;

    @Mock
    private ValidationFactory validationFactory;

    @InjectMocks
    StockExchangeController target = new StockExchangeController();

    @Test
    public void testException() throws CustomException {
        MyObj myObj = new MyObj();
        when(validationFactory.getValidator(anyString())).thenReturn(validator);
        doThrow(new CustomException()).when(validator).validate(myObj);

        ModelAndView modelAndView = target.placeOrder(new ModelAndView(), myObj);

        assertEquals("failPage", modelAndView.getViewName());
        verify(validator).validate(myObj);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM