mardi 26 juillet 2016

Stub a chained void method

I'm wondering how to stub a void method's actions when the void method is a the last method in a chain of method invocations. For example, we have the following (extremely simplified) classes:

public class MyClass {
    @Resource
    private MyDependency myDependency;

    public void put(Item item) {
        myDependency.getDao().putItem(item);
    }
}

public class MyDependency {
    @Getter
    private MyDao myDao;
}

public class MyDao {
    public void putItem(Item item) throws Exception {
        // saves item to database
        // ...
    }
}

How do we write a test for the case when a nested dependency throws an exception?

@InjectMocks
private MyClass myClass;

@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private MyDependency injectedMyDependency;

private void stubDependencyException1() throws Exception {
    doThrow(new Exception())
            .when(injectedMyDependency).getDao().putItem(any());
}

private void stubDependencyException2() throws Exception {
    doThrow(new Exception())
            .when(injectedMyDependency.getDao()).putItem(any());
}

private void stubDependencyException3() throws Exception {
    MyDao mockDao = mock(MyDao.class);
    when(injectedMyDependency.getDao()).thenReturn(mockDao);
    doThrow(new Exception()).when(mockDao).putItem(any());
}

@Test
public void test1() throws Exception {
    stubDependencyException1();

    myClass.put(new Item());
}

@Test
public void test2() throws Exception {
    stubDependencyException2();

    myClass.put(new Item());
}

@Test(expected = Exception.class)
public void test3() throws Exception {
    stubDependencyException3();

    myClass.put(new Item());
}

Test 1 - does not work because the getDao() does not throw an exception:

org.mockito.exceptions.base.MockitoException: 
Checked exception is invalid for this method!

Test 2 - fails for this reason:

org.mockito.exceptions.misusing.UnfinishedStubbingException: 
Unfinished stubbing detected here:
-> at com.blah...

E.g. thenReturn() may be missing.
Examples of correct stubbing:
    when(mock.isOk()).thenReturn(true);
    when(mock.isOk()).thenThrow(exception);
    doThrow(exception).when(mock).someVoidMethod();
Hints:
 1. missing thenReturn()
 2. you are trying to stub a final method, you naughty developer!
 3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed

Test 3 - works, but not as readable as others; does not take advantage of RETURN_DEEP_STUBS.

Is there a different way of stubbing that takes advantage of RETURN_DEEP_STUBS?

Aucun commentaire:

Enregistrer un commentaire