mocking abstract classes
Solution 1
When I want to unit test an Abstract class I don't mock, I subclass.
borrowing code from mijer in other answer
public class MockitoTest {
public static abstract class MyAbstractClass {
private int state;
public abstract int abstractMethod();
public int method(....)
{
...
}
}
}
class Testclass extends MyAbstractClass
{
public int abstractMethod()
{
...
}
}
Then run your tests of MyAbstractClass using an instance of Testclass. you can control the implementation of the abstract methods in your local subclass.
Solution 2
import org.junit.Test;
import org.mockito.internal.stubbing.answers.CallsRealMethods;
import static org.mockito.Mockito.*;
import static org.junit.Assert.*;
public class MockitoTest {
public static abstract class MyAbstractClass {
private int state;
public abstract int abstractMethod();
public void method() {
System.out.println("method. State: " + (++state));
System.out.println("abstractMethod: " + abstractMethod());
anotherMethod();
}
public void anotherMethod() {
System.out.println("anotherMethod. State: " + (++state));
}
}
@Test
public void test() throws Exception {
MyAbstractClass obj = mock(MyAbstractClass.class, new CallsRealMethods());
doReturn(5).when(obj).abstractMethod();
obj.method();
verify(obj).abstractMethod();
assertEquals(2, obj.state);
}
}
-EDIT-
If you need to maintain internal state of the object you have to use
org.mockito.internal.util.reflection.Whitebox.setInternalState
, for example:@Test public void test() throws Exception { MyAbstractClass obj = mock(MyAbstractClass.class, new CallsRealMethods()); setInternalState(obj, "state", 100); doReturn(5).when(obj).abstractMethod(); obj.method(); verify(obj).abstractMethod(); assertEquals(102, obj.state); }
If you have an abstract class with a complex logic in its constructor which you would like to test, you should extend this class just for testing or refactor your class moving all the logic to some method to be tested.
Comments
-
michael nesterenko almost 2 years
Possible Duplicate:
Using Mockito to test abstract classesI have an abstract class with functionality I need to test. I could create simple derivative of that class with no op implementations of abstract methods, but is it possible to be done with mocking framework? I need to maintain class internal state, so I can't just call
mockedInstance = mock(ClassUnderTest.class);
I need something
mockedInstance = spy(new ClassUnderTest(...));
but apparently this is impossible to do as class is abstract.
-
michael nesterenko over 12 yearsWhat if I need to pass parameters to a constructor?
-
michael nesterenko over 12 yearsintent is not to extend a class but use a mocking framework
-
michael nesterenko over 12 yearsThat is a bit cumbersome to set internal state this way. In real examples there could be much more variables, complex logic etc.
-
szhem over 12 yearsThis means you should simplify/refactor your code somehow to be more easy-testable and understandable. Moreover, it's a good practice. Why do you need to call a constructor instead of testing class methods?
-
michael nesterenko over 12 yearsI have initialization logic in constructor that needs to be executed before to be able to test methods.
-
szhem over 12 yearsIn that case you have to test real classes instead of abstract ones. I suppose it's hardly possible to extend an abstract class, to generate all corresponding constructors in the generated class, to add calls to constructors of super class, and then implement all abstract methods with current mocking frameworks.
-
Don Branson over 10 yearsThis approach is to be avoided, since you're no longer testing the class, but the subclass, and may mask or introduce bugs. It also fails to scale well as tests are added to the test fixture.