Mock services inside another service with mockito and spring

10,592 views
Skip to first unread message

André Fabbro

unread,
Sep 25, 2013, 7:48:13 AM9/25/13
to moc...@googlegroups.com
Hello friends,

I´m facing problems on mocking services inside another service injected by spring, take a look on my service:

@Service("productService")
public class ProductServiceImpl implements ProductService {

    @Autowired
    private ClientService clientService;

    public void doSomething(Long clientId) {
        Client client = clientService.getById(clientId);
        // do something
    }
}

Then, I want to mock the ClientService inside my test, so I tried the following:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:/spring-config.xml" })
public class ProductServiceTest {

    @Autowired
    private ProductService productService;

    @Mock
    private ClientService clientService;

    @Test
    public void testDoSomething() throws Exception {
        when(clientService.getById(anyLong()))
                .thenReturn(this.generateClient());

        /* when I call this method, I want the clientService
         * inside productService to be the mock that one I mocked
         * in this test, but instead, it is injecting the Spring 
         * proxy version of clientService, not my mock.. :(
         */
        productService.doSomething(new Long(1));
    }

    @Before
    public void beforeTests() throws Exception {
        MockitoAnnotations.initMocks(this);
    }

    private Client generateClient() {
        Client client = new Client();
        client.setName("Foo");
        return client;
    }
}
So, that clientService inside productService is the Spring proxy version, not the mock that I want, it is possible to get that I want with Mockito? Or isn't? Someone please help!

Thanks so much!

Eric Lefevre-Ardant

unread,
Sep 25, 2013, 8:12:52 AM9/25/13
to moc...@googlegroups.com
Well, the issue is that you are using SpringJUnit4ClassRunner on your test class and then the @Autowired annotation.
I am not well versed in how SpringJUnit4ClassRunner works, but that surely is why your ClientService instance gets a dependency from Spring.

Try removing @RunWith(SpringJUnit4ClassRunner.class).


--
You received this message because you are subscribed to the Google Groups "mockito" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mockito+u...@googlegroups.com.
To post to this group, send email to moc...@googlegroups.com.
Visit this group at http://groups.google.com/group/mockito.
For more options, visit https://groups.google.com/groups/opt_out.

André Fabbro

unread,
Sep 25, 2013, 3:09:53 PM9/25/13
to moc...@googlegroups.com
Thanks Eric, you're right, I realized there's no way to use the spring's injections in combination with mockito's mock injections... so my solution was to create the ProductService by hands and inject the mocks with @InjectMocks, like the following:

    @InjectMocks
    private ProductService productService = new ProductServiceImpl();
    @Mock
    private ClientService clientService;

    @Test
    public void testDoSomething() throws Exception {
        when(clientService.getById(anyLong()))
                .thenReturn(this.generateClient());

        productService.doSomething(new Long(1));
    }

Now it's working! Thank you very much!

Eric Lefevre-Ardant

unread,
Sep 26, 2013, 3:12:10 AM9/26/13
to moc...@googlegroups.com
Hm... I'm not sure as I'm not using @InjectMocks (I don't like its automagic approach), but I believe that you don't even need to assign productService to new ProductServiceImpl(). @InjectMocks probably does that for you.

André Fabbro

unread,
Sep 26, 2013, 8:56:12 AM9/26/13
to moc...@googlegroups.com
Hi Eric, I tested without assign new ProductServiceImpl() and it throwed the following exception:

You haven't provided the instance at field declaration so I tried to construct the instance.
However, I failed because: the type 'ProductService' is an interface.
Examples of correct usage of @InjectMocks:
   @InjectMocks Service service = new Service();
   @InjectMocks Service service;
   //also, don't forget about MockitoAnnotations.initMocks();
   //and... don't forget about some @Mocks for injection :)

at com.sys.service.ProductService.beforeTests(ProductService.java:126)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:27)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.mockito.exceptions.base.MockitoException: the type 'ProductService' is an interface.
... 29 more

So, the mockito can't instantiate the ProductService due to it is a interface....

Eric Lefevre-Ardant

unread,
Sep 26, 2013, 9:18:03 AM9/26/13
to moc...@googlegroups.com

Ah yes, I had overlooked that you had declared an interface.

That said, I believe that you should not declare an interface in your test at all. After all, your test is not testing the interface (which has nothing to test anyway), it is testing the implementation. It is really a ProductServiceImplTest.

Try just declaring the implementation.

As a side note, if you have only a single implementation of ProductService, you might considering removing the interface altogether.

Eric

André Fabbro

unread,
Sep 26, 2013, 9:58:17 AM9/26/13
to moc...@googlegroups.com
Thanks Eric! You're definitely right, when I change the field type to ProductServiceImpl the mockito was able to init it. I'll use this approach, but I can't discard the services interfaces due to spring, it have to use interfaces in order to inject services.
Thanks a lot!
Reply all
Reply to author
Forward
0 new messages