Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 719
Noam Avatar asked Dec 27 '22 00:12

Noam


2 Answers

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

like image 113
Attila Avatar answered Jan 13 '23 13:01

Attila


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);
    }
}
like image 38
jhericks Avatar answered Jan 13 '23 14:01

jhericks