Cory Kendall
Cory Kendall

Reputation: 7304

Mock a parent class to test a wrapper class

I have a class which extends another class I don't own. My class is used to calculate metrics around a few of the many calls to the parent class. Is there a way I can mock the parent class in a unit test (while preserving my child's logic) to ensure that calls made against my child always "make it through" to the wrapped parent?

In code

Class SlowClass {
    public Object doFoo(Object obj) {
        //...
    }
    public Object doBar(Object obj) {
        //...
    }

    // Many more methods I don't care about.

}

Class SlowClassWrapper extends SlowClass {
    public Object doFoo(Object obj) {
        //...
        Object toReturn = super.doFoo(obj)
        //...
        return toReturn;
    }
    public Object doBar(Object obj) {
        //...
        Object toReturn = super.doFoo(obj)
        //...
        return toReturn;
    }
}

I want to somehow mock out SlowClass.doFoo so that SlowClassWrapper.doFoo makes a call to its parent without actually making the call. I then want to confirm that obj got through untouched, and the response from SlowClass.doFoo gets back untouched.

Upvotes: 2

Views: 3758

Answers (2)

user180100
user180100

Reputation:

I would do something like that:

public class SlowClassWrapper {
    /** wrapped parent */
    public final SlowClass parent;

    public SlowClassWrapper() {
        this(new SlowClass());

    @VisibleForTesting
    protected SlowClassWrapper(SlowClass parent) {
        this.parent = parent;
    }

    public Object doFoo(Object obj) {
        //...
        Object toReturn = parent.doFoo(obj)
        //...
        return toReturn;
    }

    public Object doBar(Object obj) {
        //...
        Object toReturn = parent.doFoo(obj)
        //...
        return toReturn;
    }
}

Using Mockito and JUnit

@RunWith(MockitoJUnitRunner.class)
public class SlowClassWrapperTest {
     /** parent mock */
     @Mock
     private SlowClass parentMock;

     /** instance under tests */
     private SlowClassWrapper instance;

     @Before
     public void setUp() {
         this.instance = new SlowClassWrapper(this.parentMock);
     }

     @Test
     public void testDoFoo() {
         final Object obj1 = new Object();
         final Object obj2 = new Object();
         Mockito.doReturn(obj2).when(this.parentMock).doFoo(Matchers.any());
         assertEquals(obj2, this.instance.doFoo(obj1));
         Mockito.verify(this.parentMock).doFoo(obj1);
         Mockito.verifyNoMoreInteractions(this.parentMock);
     }

     @Test
     public void testDoBar() {
         final Object obj1 = new Object();
         final Object obj2 = new Object();
         Mockito.doReturn(obj2).when(this.parentMock).doBar(Matchers.any());
         assertEquals(obj2, this.instance.doBar(obj1);
         Mockito.verify(this.parentMock).doBar(obj1);
         Mockito.verifyNoMoreInteractions(this.parentMock);
     }
}

(not tested)

Upvotes: 1

Jordan Lewis
Jordan Lewis

Reputation: 17938

In general, this is not something that mocking frameworks can happily do in Java. You might want to consider restructuring your code to use composition instead of inheritance. Then, you could inject the SlowClass instance into the wrapper's constructor, allowing easy testability through regular mocking.

For what it's worth, neither Mockito nor PowerMock can mock out super methods: see this answer and this discussion.

Upvotes: 4

Related Questions