Unit testing a method of a class that has a constructor and an autowired field that needs to be mocked using mockito

1.7k Views Asked by At

I have a service class that extends another service with a constructor. This class has an autowired field and a method that I wanted to unit test using Mockito. However, I am having trouble writing a unit for it.

Let say the service looks somewhat like this:

@Service
public class SomeService extends Service {

    @Autowired
    private SomeClient someClient;

    public SomeService(Product product, @Qualifier(Constants.SOME_BEAN) Details temp) {
        super(product, temp);
    }
    @Override
    public State create() {
        Request request = new Request();
        request.set...
        request.set..

        Status status = someClient.createTenant(request);
        ..
        .. // construct a State object and return
    }
}

Now, I am writing a test for this class and I am trying to unit test the method create() above. I am having trouble mocking someClient there when this method is called by my test.

The test class looks somewhat like:

@RunWith(MockitoJUnitRunner.class)
public class SomeServiceTest {
    private Detail temp;

    private SomeFacade service;

    private SomeClient someClient;

    private Product product;

    @Before
    public void setup() {
        temp = mock(Details.class);
        product = mock(Product.class);
        service = spy(new SomeService(product, temp));
        someClient = mock(SomeClient.class);
    }

    @Test
    public void test() {
        Status status = new Status();
        status.setStatus(...);
        when(someClient.createTenant(any())).thenReturn(status);
        State state =  service.create();

        // asserts
    }
}   

What I want to is that when I call service.create in the test above, the call someClient.createTenant(request); in the method tested should be mocked to return a value and this is something I am not able to get working. Any help?

2

There are 2 best solutions below

6
Turing85 On

We can use Mockito's @InjectMocks-annotation to inject mocks into our unit under test. For this, we also need to

  • remove mock intialization from the setup()-method and
  • annotate the mocks with @Mock

Remarks:

  • Instead of field injection, I would recommend constructor injection. This allows, among other things, to keep the structure of the code and create the unit under test within setup() by manual injection
  • I would also recommend to add a type to the when: when(someClient.createTennant(any(Request.class)))...
  • As was pointed out by @second, the spy on the unit under test is superfluous.
  • Also pointed out by @second was the fact that field injection will not work if a constructor is present
0
Ngoc Dinh Cong On

In this case you don't need to use @InjectMocks and @Mock. Let's init your target class by using constructor

i.e: 
Product product = Mockito.mock(Product.class);
...
SomeService service = new SomeService(product,...);

Then use ReflectionTestUtils to init @Autowire fields by Mockito class

i.e:
SomeClient someClient = Mockito.mock(SomeClient.class);
ReflectionTestUtils.setField(service, "someClient", someClient);