Noam
Noam

Reputation: 3145

How can I know if a method was invoked on the unit under test?

I'm writing a new class (Derived), in TDD, using mockito and I have the following case:

Class Base:

public abstract class Base<T>{
    //.......
    protected final T baseCreate(T entity){
        // implementation
    }
}

Class Derived ( This is the class that I'm writing using TDD ):

public class Derived extends Base<MyObject> {
    //.......
    public MyObject create(MyObject entity){
        baseCreate(entity);    //This is what I want the implementation to be
    }
}

When I came to write a test the will force me to invoke the baseCreate method - I failed to understand how to do that. Is there a way, using mockito, to verify that the create(...) method in Derived invokes the baseCreate(...) method in the Base class?

Thanks.

Upvotes: 4

Views: 297

Answers (3)

Dawood ibn Kareem
Dawood ibn Kareem

Reputation: 79838

You say you're using TDD - so presumably, there's some specification of the required behaviour of either Derived or Base or both. So you'll write some tests around that specification. Those tests won't require you to make Derived extend Base - they'll simply require certain behaviour of each class; and it will be behaviour that you can implement without using inheritance at all.

Once your tests pass, then the next stage of TDD kicks in. This is the "refactor" stage, where you look for improvements in the way your classes are designed. This is the point at which you'll decide to make Derived extend Base, and make the create method call baseCreate. The wonderful thing is that when you do the refactor, you've already got some tests, to make sure that it has worked correctly.

Upvotes: 1

jhericks
jhericks

Reputation: 5971

Attila is right for most cases. What you want to test is that create actually does what you think it should do, not how it does it. The case you have here sounds like, "I already know that baseCreate does what I want it to do, so I don't want to re-test that, just that it gets called." This could be the case, but if so, then your superclass is really more of a collaborator. It's part of the reason to favor delegation over inheritance. Nonetheless, sometimes it is difficult to go back and change that design decision, so you have to test what you have.

You should still favor just checking that "create" does what you want it to do on the whole, but you might have a case where baseCreate is really doing a lot of stuff that requires a lot of set up of collaborators and such which makes it difficult and brittle to test. In that case, you would want to use a "spy". A spy wraps a "real" object and delegates to the real method calls unless you specifically create another expectation.

If you could make baseCreate public, you could use Mockito like this:

@RunWith(MockitoJUnitRunner.class)
// We prepare PartialMockClass for test because it's final or we need to mock private or static methods
public class YourTestCase {
    @Spy
    private Derived classUnderTest = new Derived();

    @Test
    public void privatePartialMockingWithPowerMock() {        
        MyObject myObject = new MyObject();
        when(classUnderTest.baseCreate(myObject)).thenReturn(myObject);

        // execute your test
        classUnderTest.create(myObject);

        verify(classUnderTest).baseCreate(myObject);
    }
}

If you can't make baseCreate public, I think you could use PowerMock. It lets you verify private methods, but I don't think there would be any reason it couldn't do protected methods, too.

@RunWith(PowerMockRunner.class)
// We prepare PartialMockClass for test because it's final or we need to mock private or static methods
@PrepareForTest(Derived.class)
public class YourTestCase {
    @Test
    public void testCreate() {        
        Derived classUnderTest = PowerMockito.spy(new Derived());
        MyObject myObject = new MyObject();

        // use PowerMockito to set up your expectation
        PowerMockito.doReturn(myObject).when(classUnderTest, "baseCreate", myObject);

        // execute your test
        classUnderTest.create(myObject);

        // Use PowerMockito.verify() to verify result
        PowerMockito.verifyPrivate(classUnderTest).invoke("baseCreate", myObject);
    }
}

Upvotes: 4

Attila
Attila

Reputation: 28762

Unit tests are to test the behavior of the class, not its implementation. So you should not concern yourself with whther the Base's baseCreate() is called explicitly, rather wheter calling Derived's cerate() does exactly as you expect from an external observer's perspective

Upvotes: 5

Related Questions