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.