Hot questions for Using Mockito in abstract class

Top 10 Java Open Source / Mockito / abstract class

Question:

How to use Mockito or PowerMock to mock a protected method that is realized by a subclass, but inherited from an abstract super class?

In other words, I want to test "doSomething" method while mocking the "doSomethingElse".

Abstract super class

public abstract class TypeA {

    public void doSomething() {     

        // Calls for subclass behavior
        doSomethingElse();      
    }

    protected abstract String doSomethingElse();

}

Subclass implementation

public class TypeB extends TypeA {

    @Override
    protected String doSomethingElse() {
        return "this method needs to be mocked";
    }

}

Solution

Answers given here are correct and will work if classes involved are in the same package.

But if different packages are involved one option is to user PowerMock. The following example worked for me. Of course there might be other ways of doing it, this is one that works.

import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest({ TypeB.class })
public class TestAbstract {

    @Test
    public void test_UsingPowerMock() throws Exception {
        // Spy a subclass using PowerMock
        TypeB b = PowerMockito.spy(new TypeB());
        String expected = "some value for mock";

        // Mock a method by its name using PowerMock again
        PowerMockito.doReturn(expected).when(b, "doSomethingElse");

        // Calls the 
        String actual = b.doSomething();
        assertEquals(expected, actual);     

    }
}

Note: Tests done using Java 5, jUnit 4.11, Mockito 1.9.0 and PowerMock 1.4.12.


Answer:

You can use Mockito.CALLS_REAL_METHODS when mocking the abstract method. This will call the originals methods of the class and you can mock all abstract methods by yourself.

TypeA typeA = mock(TypeA.class, Mockito.CALLS_REAL_METHODS);
when(typeA.doSomethingElse()).thenReturn("Hello");
typeA.doSomething();

Or you test directly on the TypeB with a spy:

TypeB typeB = spy(new TypeB());
when(typeB.doSomethingElse()).thenReturn("Hello");
typeB.doSomething();

Question:

I have an abstract class BaseTemplate and multiple classes extending it. In one of the concrete class(SmsTemplate extends BaseTemplate), we have a private variable Gson. We have the same private variable(Gson) in the abstract class as well.

While unit tesing the concrete class, methods in the abstract class is getting called from the concrete class. In my Unit test, I am using Whitebox.setInternalState(smsTemplateObj, gsonObj); to inject the Gson object into the private members of SmsTemplate and BaseTemplate but the Gson is getting injected only in the subclass. In abstract class, its NULL, meaning not injected. Below is the implementation.

Can someone please tell how to inject the Gson object in the abstract class?

abstract class BaseTemplate{

    private Gson gson;//Here its not getting injected

    protected String getContent(Content content){
        return gson.toJson(content); // ERROR - gson here throws NPE as its not injected
    }
}

class SmsTemplate extends BaseTemplate{

    private Gson gson;//Here its getting injected

    public String processTemplate(Content content){
        String strContent = getContent(content);
        ...
        ...
        gson.fromJson(strContent, Template.class);
    }
}

Answer:

Whitebox.setInternalState() method will only set the value of the first field it encounters going up through the hierarchy of the object you pass. So once it finds gson field in your subclass, it won't look further and won't change the superclass field.

There are two solutions for this case:

  • Change the variables names. If the variables have different names, you can simply invoke Whitebox.setInternalState() twice, one for each variable.
  • Set the field manually using reflection. You can also just set the field without Mockito's help using something like the following snippet.

Snippet:

Field field = smsTemplateObj.getClass().getSuperclass().getDeclaredField("gson");
field.setAccesible(true);
field.set(smsTemplateObj, gsonObj);

Question:

Is it possible to both mock an abstract class and inject it with mocked classes using Mockito annotations. I now have the following situation:

@Mock private MockClassA mockClassA;
@Mock private MockClassB mockClassB;

@Mock(answer = Answers.CALLS_REAL_METHODS) private AbstractClassUnderTest abstractClassUnderTest;

@Before
public void init() {
    MockitoAnnotations.initMocks(this);
    Whitebox.setInternalState(abstractClassUnderTest, mockClassA);
    Whitebox.setInternalState(abstractClassUnderTest, mockClassB);
}

I'd like to use something like @InjectMocks on AbstractClassUnderTest but it can't be used in combination with @Mock. The current situation, with Whitebox from Powermock, works but I'm curious if it's possible to solve it with just annotations. I couldn't find any solutions or examples.

(I know about the objections to test abstract classes and I'd personally rather test a concrete implementation and just use @InjectMocks.)


Answer:

I am not aware of any way to go about this, for one clear reason: @InjectMocks is meant for non-mocked systems under test, and @Mock is meant for mocked collaborators, and Mockito is not designed for any class to fill both those roles in the same test.

Bear in mind that your @Mock(CALLS_REAL_METHODS) declaration is inherently dangerous: You're testing your AbstractClassUnderTest, but you are not running any constructors or initializing any fields. I don't think you can expect a test with this design to be realistic or robust, no matter what annotations can or cannot do for you. (Personally, I was previously in favor of real partial mocks of abstract classes as a "tool in the toolbox", but I'm coming around to thinking they're too far removed from reality to be useful.)

Were I in your position, I would create a small override implementation for testing:

@RunWith(JUnit4.class) public class AbstractClassTest {
  /** Minimial AbstractClass implementation for testing. */
  public static class SimpleConcreteClass extends AbstractClass {
    public SimpleConcreteClass() { super("foo", "bar", 42); }
    @Override public void abstractMethod1() {}
    @Override public String abstractMethod2(int parameter) { return ""; }
  }

  @InjectMocks SimpleConcreteClass classUnderTest;
  @Mock mockClassA;
  @Mock mockClassB;
}

At this point, you have a simple and predictable AbstractClass implementation, which you can use even without a mocking framework if you just wanted to test that AbstractClass has the same API for extension that it did before. (This is an often-overlooked test for abstract classes.) You can even extract this, as it may be useful for other testing: Should you want to override the abstract behavior for a single test class, you can create an anonymous inner class with just a single method override, or you can set classUnderTest = spy(classUnderTest); to set up Mockito proxying and the behavior you want.

(Bear in mind that @InjectMocks and @Spy can't be used reliably together, as documented in this GitHub issue and the Google Code and mailing list threads to which it links.)

Question:

I've seen one other example of this question on Stack, but no answers. Can anyone tell me based on experience (or any other esoteric means) if this is even possible to do? I've followed all of the examples I could find of mocking static methods I could find, but haven't found one that works for static methods in abstract classes. Two methods fail with MissingMethodInvocationException:

File[] files = {goodFile, badFile};
PowerMockito.mockStatic(AbstractFileImporter.class);

// fails with MissingMethodInvocationException
PowerMockito.when(AbstractFileImporter.getFiles(".")).thenReturn(files);

And:

// fails with MissingMethodInvocationException
BDDMockito.given(AbstractFileImporter.getFiles(".")).willReturn(files);

Whereas this method fails with IllegalStateException:

// fails with IllegalStateException
expect(AbstractFileImporter.getFiles(".")).andReturn(files);

I'm pretty new to mocking, so any advice or good site links to use as resources while trudging through all of this would be really helpful. By the way, I do have some leeway with regard to refactoring, but not on using different tools/utilities, so I'm stuck with Mockito/PowerMock and TestNG.


Answer:

Okay, I tried to convert my example to TestNG and it worked for me after following the example at https://code.google.com/p/powermock/wiki/TestNG_usage.

I get the MissingMethodInvocationException you mentioned when I'm omitting the required test class annotation @PrepareForTest(AbstractAnimal.class).

I'm using eclipse 4.4.1 with the TestNG plugin version 6.8.6.

See below for my converted example and the dependencies. Also, notice the extension of PowerMockTestCase. I did not change the sample class AbstractAnimal.

import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.testng.PowerMockTestCase;
import org.testng.Assert;
import org.testng.annotations.Test;

@PrepareForTest(AbstractAnimal.class)
public class AbstractAnimalTest extends PowerMockTestCase {

    @Test
    public void shouldGetMockedHello() {
        PowerMockito.mockStatic(AbstractAnimal.class);
        PowerMockito.when(AbstractAnimal.getHello()).thenReturn("Hello mocked animal world!");

        String greetings = AbstractAnimal.getHello();
        Assert.assertTrue(greetings.equals("Hello mocked animal world!"));
    }

}

Dependendencies (I tried to use your versions):

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.gnollix.stackoverflow</groupId>
    <artifactId>mock-static-abstract</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>6.8.8</version>
        </dependency>
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-module-testng</artifactId>
            <version>1.5.6</version>
        </dependency>
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-api-mockito</artifactId>
            <version>1.5.6</version>
        </dependency>
    </dependencies>

</project>

Resolved dependencies:

Hope that's useful!

Question:

In a class under test, if its constructor takes in an abstract class parameter can we mock it using mockito?

Ex

public abstract AbstractClass{
} 

//Class under test
public class SourceClass{            
  SourceClass(AbstractClass abstractClass){}            
}

@RunWith(MockitoJUnitRunner.class
public SourceClassTest{
 @Mock
  AbstractClass abstractClass;
}

whenever I do this i get this error

java.lang.ExceptionInInitializerError

Ther version of mockito I am using i 1.8.5


Answer:

Well, this code below works fine, just tell me if I need to add some comments to explain what I wrote, ok? (hey, I am using Mockito 1.10.8):

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;

abstract class AbstractClassToTest {
    public abstract String doSomething();
}

class ConcreteClass {

    private String something;

    public ConcreteClass(AbstractClassToTest aClass){
        this.something = aClass.doSomething();
    }

    public String getSomething(){
        return this.something;
    }
}

@RunWith(MockitoJUnitRunner.class)
public class TempTest {

    @Mock
    private AbstractClassToTest myClass;

    @Test
    public void canAbstractClassToTestBeMocked() {
        String expectedResult = "hello world!";
        Mockito
            .when(myClass.doSomething())
            .thenReturn(expectedResult);

        String actualResult = myClass.doSomething();

        Assert.assertEquals(expectedResult, actualResult);
    }

    @Test
    public void canConcreteClassBeInstantiatedWithMock() {
        String expectedResult = "hello world!";
        Mockito
            .when(myClass.doSomething())
            .thenReturn(expectedResult);

        ConcreteClass concrete = new ConcreteClass(myClass);

        String actualResult = concrete.getSomething();

        Assert.assertEquals(expectedResult, actualResult);
    }
}

Question:

I have an abstract class B which extend another abstract class A. In abstract class A I have protected method convert. I want to test method foo which invoke method convert from base class which doesn't have implementation. How I can mock method convert if I can't change convert method signature.

abstract class B extends A {
    public void foo(Object someObject) {
        Object convertedObject = convert(someObject);
        //logic for testing
    }
}

abstract class A {
    protected abstract Object convert(Object some object);      
}

I use Mockito.spy() for invoking real methods but convert method is not available for mocking (throught Mockito.when (...).thenReturn (...) because it is protected.

B b = Mockito.spy(B.class);

Give me idea how I can test method foo.


Answer:

Mockito can't mock abstract classes. But you can have a subclass for your test purpose which implement your class B and then spy on it.

@RunWith(MockitoJUnitRunner.class)
public class BTest {

    @InjectMocks
    @Spy
    private FakeB b;

    @Test
    public void testSomething() {
        when(b.convert(any())).thenReturn(something);
    }

    public static class FakeB extends B {
        protected Object convert(Object someobject) {
            return null;
        }  
    }
}

With this approach you can easily mock your abstract methods and test non-abstract ones in your abstract classes. Of course the downside is that you have to crate a fake test classes that subtypes your abstract classes. But I think it shouldn't be a big issue.

Question:

I have an abstract class, say AbstractClass where I've got a public void method myMethod without an implementation. While I'm testing this class, I've created an anonymous subclass, where I can implement myMethod as I see fit. In AbstractClass There's another method, say myImplementedMethod which calls myMethod. Is there a trick to what I can put in myMethod in the anonymous subclass, so as to be able to verify that it has been called?

Edit: I'm using Mockito for mocking, and it is not my place to use another framework.

public abstract class AbstractClass {
    public abstract void myMethod();

    public void myImplementedMethod() {
        myMethod();
}

public class AbstractClassTest {

    @Before
    public void setUp() {
        AbstractClass myClass = new AbstractClass() {

            @Override
            public void myMethod(){
                //What could I put here?
            }
        }
    }

    @Test
    public void testMyImplementedMethod() {
        myClass.myImplementedMethod();
        //check that myMethod is called.
    }
}

Answer:

If Mockito's spy works for you, great. However I don't believe it will capture internal method calls. How about the below...

public class AbstractClassTest {

 boolean methodCalled = false;

@Before
public void setUp() {
    methodCalled = false;
    AbstractClass myClass = new AbstractClass() {

        @Override
        public void myMethod(){
            methodCalled = true;
        }
    }
}

@Test
public void testMyImplementedMethod() {
    assertFalse(methodCalled);
    myClass.myImplementedMethod();
    assertTrue(methodCalled);
}
}

Question:

Here I go:

abstract class IdentifiedEntity<E extends IdentifiedEntity> implements Cloneable {
  ...
  public void updateWith(E that) {
    if (this != that) {
      if (that.isNew()) {
        throw new IllegalArgumentException("Cannot update with a new entity");
      }
      if (this.isNew()) {
        throw new IllegalStateException("Cannot update a new entity");
      }
      if (this.getId() != that.getId()) {
        throw new IllegalArgumentException("IDs do not match");
      }
      doUpdateWith(that);
    }
  }

  abstract void doUpdateWith(E that);
  ...
}

public final class User extends IdentifiedEntity<User> {
  ...
  @Override
  void doUpdateWith(User that) {
    assert that != null;
    this.name = that.name;
    this.email = that.email;
    System.arraycopy(that.password, 0, password, 0, password.length);
    this.enabled = that.enabled;
    this.caloriesPerDayLimit = that.caloriesPerDayLimit;
  }
  ...
}

The question is how can I unit test the updateWith(...) to ensure that it definely invokes the abstract doUpdateWith(...) implmented in the descendant (yes, for sure,if i tpasse sall the checks)?

That you guys!


Answer:

Create a dummy sub class

class ConcreteEntity extends IdentifiedEntity<ConcreteEntity> {
  @Override
  void doUpdateWith(ConcreteEntity that) {
  }
}

then test like this:

@Test
public void test() throws Exception {
    ConcreteEntity e = Mockito.spy(new ConcreteEntity());
    e.updateWith(e);

    Mockito.verify(e).doUpdateWith(e);
}

However such a test is very special. It does not allow you to change implementation of your method.

Question:

There is some interface called say called Foo.

interface Foo {
    void add(Object key, Object value);
    Object get(Object key);
    void someOtherMethodUnessentialToTesting();
}

There is an implementation in the test called MockFoo that implements most methods in a "default" way (doing nothing, returning null, basically only implementing them so it compiles). However, it implements a couple to give real functionality, and they are methods that insert and read from a Map. (If the last bit wasn't essential I would just use a Mockito mock and wouldn't even be asking.)

// The current "bad mock"
class MockFoo implements Foo {

    Map<Object, Object> map = new ...

    @Override
    void add(Object key, Object value) {
        map.put(key, value);
    }

    @Override
    Object get(Object key) {
        map.get(key);
    }

    @Override
    void someOtherMethodUnessentialToTesting()
    {}   
}

The problem is that because this is not a Mockito mock, every time the interface changes the test has to be updated. Yes, people should check better to fix all implementations of the interface they change, but there really shouldn't be an implementation in the test in the first place in my opinion.

I am confused on how to solve this. My instinct is to make it abstract and implement only those methods then mock it somehow so that it calls those "real" methods when it needs them. I read that Mockito has a thenDoRealMethod() for stubs but this is only for returning values so it would not work on a void method.

// My abstract class I was trying to stub somehow
abstract class FooForTest implements Foo {

    Map<Object, Object> map = new ...

    @Override
    void add(Object key, Object value) {
        map.put(key, value);
    }

    @Override
    Object get(Object key) {
        map.get(key);
    } 
}

I realize this may be a design issue and adding in an AbstractFoo in the real code is probably best (because the add and get won't change really) but I am more curious if there is a way to fix this once-and-for-all just by modifying the test code.


Answer:

Using a technique like in this SO answer, you can use CALLS_REAL_METHODS as a default answer—or, as you suggested, you can use the default answer (RETURNS_DEFAULTS) and individually stub certain methods to call your fake. Because you want Mockito's behavior to show through, I'd recommend the latter.

There's an equivalent to thenCallRealMethod for void methods: doCallRealMethod. You need to start with do because when(T value) has no value to take [and subsequently ignore].

abstract class FooForTest implements Foo {

    public static Foo create() {
        FooForTest mockFoo = mock(FooForTest.class);
        mockFoo.map = new HashMap<>();
        when(mockFoo.get(any())).thenCallRealMethod();
        doCallRealMethod().when(mockFoo).add(any(), any());
        return mockFoo;
    }        

    Map<Object, Object> map = new ...

    @Override
    void add(Object key, Object value) {
        map.put(key, value);
    }

    @Override
    Object get(Object key) {
        map.get(key);
    }
}

Without complicated reflection, I can't think of any way to automatically let Mockito call real methods for unimplemented methods only. If you were to write an Answer for that, though, you could use it for all methods by passing it into the call to mock. You will also need to initialize your field explicitly in your create method, as the mock is not a real object and will not be properly initialized.

Another alternative would be to have empty method stubs, and use spy() instead; this would solve some of the initialization concerns.


This technique is called partial mocking, and beware that it can act as a code smell—specifically, that the class under test is violating the Single Responsibility Principle. In any case you should be very careful when adding methods to widely-implemented interfaces, for all of these reasons, and consider AbstractFoo (or a fully-implemented FakeFoo) as sensible upgrades later.