7

I'd like to use Mockito to unit test an abstract class as detailed in this great answer.

The trick is, the abstract class has a dependency on a strategy that gets injected in its constructor. I've created a mock of the strategy and I'd like for my mocked instance of BaseClass to use the mocked strategy for my unit test.

Any suggestion as to how I can wire this up? I'm not currently using any IoC framework, but am considering Spring. Perhaps it would do the trick?

// abstract class to be tested w/ mock instance
abstract BaseClass
{
    // Strategy gets mocked too 
    protected BaseClass( Strategy strategy)
    {
        ...
    }
}

Update:
According to the Mockito mailing list, there currently isn't a way to pass arguments to the constructor of a mock.

Community
  • 1
  • 1
HolySamosa
  • 9,011
  • 14
  • 69
  • 102

3 Answers3

6

I ended up just using reflection to set a private field in my base class, like so:

// mock the strategy dependency
Strategy strategyMock = mock( Strategy.class);
when(....).thenReturn(...);

// mock the abstract base class
BaseClass baseMock = mock(BaseClass.class, CALLS_REAL_METHODS);

// get the private streategy field
Field strategyField = baseMock.getClass().getSuperclass().getDeclaredField("_privateStrategy");

// make remove final modifier and make field accessible
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(strategyField, strategyField.getModifiers() & ~Modifier.FINAL);          
strategyField.setAccessible(true);

// set the strategy
strategyField.set(baseMock, strategyMock);

// do unit tests with baseMock
...

It would break if the name of the private field ever changed, but its commented and I can live with that. It's simple, it;s one line of code and I find this preferable to exposing any setters or having to explicitly subclass in my tests.

Edit: So it's not one line of code anymore since my private field needed to be 'final', requiring a some extra reflection code to get around.

HolySamosa
  • 9,011
  • 14
  • 69
  • 102
  • 1
    Great post! You can do all of this with one line if you have a Spring dependency ;-). Found this class while snooping around Spring's box of goodies. `org.springframework.test.util.ReflectionTestUtils.setField(baseMock, "_privateStrategy", strategyMock)` – Matt Byrne Sep 02 '13 at 23:44
5

Ive seen this sort of thing done using Mockito at a spring context level.

eg:

<bean id="myStrategy" name="myStrategy" class="org.mockito.Mockito" factory-method="mock">
    <constructor-arg value="Strategy" />
</bean>

I hope that helps.

Klee
  • 2,022
  • 3
  • 23
  • 32
0

You don't need to do anything special. Just mock the bean like normal:

Bean bean = mock(Bean.class); 
when(bean.process()).thenReturn(somethingThatShouldBeNamedVO);

Just works :)

Peter Bratton
  • 6,302
  • 6
  • 39
  • 61
  • Thanks, Jordan! Unfortunately, I don't think it will work for my case since I need specific mocked behavior in the strategy class injected into the base. If a default mock of the strategy (that just returns null, 0, etc.) was used the logic of the mocked BaseClass would break. Thanks, though! – HolySamosa Apr 17 '12 at 15:11
  • This does not answer the question. – Christopher Roscoe Mar 14 '16 at 15:57