Reputation: 7304
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
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
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