Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Injection of a mock object into an object to be tested declared as a field in the test does not work using Mockito?

Tags:

java

mockito

I have a class and I am injecting a proxy into my service.

Service service
{
    private ServiceProxy proxy;
    public Service(ServiceProxy proxy)
    {
        this.proxy = proxy; 
    }
}

The test for it is:

ServiceTest
{
    @Mock
    ServiceProxy mockProxy;
    Service service = new Service(mockProxy);
}

If I initialize my class like this I always get a NPE when I want to use the service object. Why does Mockito do this? What is an easy way around this instead of declaring it in each and every test?

like image 487
Phoenix Avatar asked Oct 25 '13 02:10

Phoenix


1 Answers

Provided you are using Mockito version 1.9.0 or later, the best way to achieve what you want is like this:

@RunWith(MockitoJUnitRunner.class)
public class ServiceTest {

    @Mock
    private ServiceProxy proxy;

    @InjectMocks
    private Service service;

    @Test
    public void test() {
        assertNotNull(service);
        assertNotNull(proxy);
    }
}

First thing is the @RunWith(MockitoJUnitRunner.class) declaration which will cause @Mock and @InjectMocks annotation to work automatically without any explicit initialization. The second thing is that starting with Mockito 1.9.0 @InjectMocks annotation can use the Constructor injection mechanism which is the best option for your Service class.

Other options for @InjectMocks are Setter injection and Field injection (see docs BTW) but you'd need a no argument constructor to use them.

So summarizing - your code cannot work because:

  • you are not using the MockitoJUnitRunner nor MockitoAnnotations.initMocks(this) so @Mock annotation takes no effect
  • even if above were satisfied your example would fail because mockProxy would be initialized after the test is constructed and your service is tried to be initialized during the test class construction, hence it receives null mockProxy reference.

If for some reason you don't want to use @InjectMocks, the only way is to construct your Service object within the test method body or within the @Before annotated setUp method.

like image 64
macias Avatar answered Oct 30 '22 10:10

macias