Unit-testing – How to use PowerMock / Mockito / EasyMock to use a mocked object for dependency injection

dependency-injectionmockingunit testing

I have an AuthenticationManager.authenticate(username,password) method that gets called in someMethod of a SomeService under test. The AuthenticationManager is injected into SomeService:

@Component
public class SomeService {
    @Inject
    private AuthenticationManager authenticationManager;

    public void someMethod() {
        authenticationManager.authenticate(username, password);
        // do more stuff that I want to test
    }
}

Now for the unit test I need the authenticate method to just pretend it worked correctly, in my case do nothing, so I can test if the method itself does the expected work (Authentication is tested elsewhere according to the unit testing principles, however authenticate needs to be called inside that method)

So I am thinking, I need SomeService to use a mocked AuthenticationManager that will just return and do nothing else when authenticate() gets called by someMethod(). How do I do that with PowerMock (or EasyMock / Mockito, which are part of PowerMock)?

Or is there another way to tell Spring to use some Mock instead of the real deal, when injeeting the AuthenticationManager into SomeService?

Or is my design wrong?

Thanks!


Edit – found a solution, would like to hear comments

So I found a nice way to inject a mock without having to use a setter or package level:

@RunWith(PowerMockRunner.class)
public class TestOrderService {

    @Mock
    private AuthenticationManager authenticationManager;

    @InjectMocks 
    private OrderService orderService = new OrderService();

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
        Mockito.doNothing().when(this.authenticationManager).authenticate(null, null);
    }

    @Test
    public void testOrderService() {
        orderService.save(null, null, null);
    }
}

with OrderService like this:

public void save(String username, Order order) {
    authenticationManager.authenticate(username, password);
    // do something with the order...
}

Now the save method will call authenticate on the mock and the mock does nothing leaving me free to test the actual work inside my service method (which actually is calling a manager method but that was not the point 😉 )

Best Answer

I personally don't use spring on the unit testing side (except maybe a single test to verify that the application context loads properly). Instead I use setter methods to manually wire the mocks (actually I use project lombok's @Setter annotation), OR if I'm using @Autowired I make the member variables package scoped so the unit test can directly set the values.

I don't see how you're going to get things like Mockito to work via dependency injection, because you'll always be new-ing your object inside the unit test and then creating mock behaviors for the methods. Also, you don't lose much by doing it this way, because you'll only need to setup direct dependencies of the class under test (because they're mocks), which is much easier than what spring DI does, which is recursive dependency creation and wiring on real objects.