Search code examples
junitmockitohk2

How to use Mockito with HK2?


I'm using HK2 for dependency injection and want to replace a Singleton Object with a Mockito-mock in the context of a JUnit-Test.

The simplest setting would be as follows:

import javax.inject.Inject;
import org.jvnet.hk2.annotations.Service;

@Service
public class A {

    @Inject
    private B b;

    public String test() {
        return b.toString();
    }

}

@Service
public class B {

    public String toString()
    {
        return "B";
    }

}

whereas the JUnit-Test stub is as follows:

import static org.junit.Assert.*;

import javax.inject.Inject;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.jvnet.hk2.testing.junit.HK2Runner;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class MockTest extends HK2Runner {

    private B bMock = Mockito.mock(B.class);

    @Inject
    private A a;

    @Test
    public void test() {
        Mockito.when(bMock.toString()).thenReturn("Mock");
        assertEquals("Mocking worked", "Mock", a.test());
    }

}

I want the Mock for B to be injected into A and not the real Object. How can I configure HK2 globally, such that for every instance of B the mock is used? I already know that I could inject B locally into A by using injection via constructor.


Solution

  • Have you considered using a @Stub of B rather than a Mock?. To do that you can add @Contract onto the implementation of B:

    @Service @Contract
    public class B {
    
        public String toString()
        {
            return "B";
        }
    
    }
    

    and rather than using the mock use a @Stub:

    public class MockTest extends HK2Runner {
    
        @Inject
        private A a;
    
        @Test
        public void test() {
            assertEquals("Mocking worked", "Mock", a.test());
        }
    
        @Stub @Rank(1)
        public static abstract class BStub extends B {
            public String toString() {
                return "Mock";
            }
    
        }
    
    }
    

    In order for this to work the hk2-metadata-generator should be in the classpath of your test during compilation so it can generate the stub. You put @Rank(1) on the stub to ensure it gets picked over the original B class.

    Hope this helps!