2

Possible Duplicate:
Using Mockito to test abstract classes

I 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.

Community
  • 1
  • 1
michael nesterenko
  • 14,222
  • 25
  • 114
  • 182
  • 3
    possible duplicate of [Using Mockito to test abstract classes](http://stackoverflow.com/questions/1087339/using-mockito-to-test-abstract-classes). See [this answer](http://stackoverflow.com/questions/1087339/using-mockito-to-test-abstract-classes/4317631#4317631). – Yishai Nov 17 '11 at 17:07

2 Answers2

2

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.

Aaron
  • 874
  • 3
  • 17
  • 34
1
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-

  1. 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);
    }
    
  2. 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.

szhem
  • 4,672
  • 2
  • 18
  • 30
  • What if I need to pass parameters to a constructor? – michael nesterenko Nov 17 '11 at 17:36
  • That is a bit cumbersome to set internal state this way. In real examples there could be much more variables, complex logic etc. – michael nesterenko Nov 18 '11 at 07:59
  • This 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? – szhem Nov 18 '11 at 08:41
  • I have initialization logic in constructor that needs to be executed before to be able to test methods. – michael nesterenko Nov 18 '11 at 09:44
  • In 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. – szhem Nov 18 '11 at 11:32