1

Mockito annotations @Spy or @InjectMocks won't work on Interfaces:

public interface MyService() {}

public class MyServiceImpl implements MyService {}


@RunWith(MockitoJUnitRunner.class)
public class MyServiceTest {

    @Spy
    @InjectMocks
    private MyService myService; // won't work

    @Mock
    MyDao myDao;

    // tests
}

From the documentation on Spy (something similar for @InjectMocks):

The field annotated with @Spy can be initialized by Mockito if a zero argument constructor can be found in the type (even private). But Mockito cannot instantiate inner classes, local classes, abstract classes and interfaces. The field annotated with @Spy can be initialized explicitly at declaration point. Alternatively, if you don't provide the instance Mockito will try to find zero argument constructor (even private) and create an instance for you. But Mockito cannot instantiate inner classes, local classes, abstract classes and interfaces.

So I understand that I cannot use an Interface to Spy on. It works when I use an actual implementation class when declaring/initializing the Interface.

Which of the solutions below would be the best to deal with these kind of issues?

Solution 1:

    @InjectMocks
    private MyService myService = new MyServiceImpl(); // Program against Interface

Solution 2:

    @Spy
    @InjectMocks
    private MyServiceImpl myService; // Program against implementation

My question is whether it's a good idea to use solution 2 and let Mockito handle the instantiation (but that means declaring an implementation instead of an interface) OR use solution 1 with an interface and do the declaration of an implementation myself.

Diyarbakir
  • 1,999
  • 18
  • 36
  • 1
    But this is [XY problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). Spying on `MyService` makes no sense since it is an interface. What do you really want to achieve here? – Tunaki Apr 28 '16 at 10:52
  • 1
    If you want to test the implementation why are you spying it? – Tunaki Apr 28 '16 at 11:10
  • Unit-tests are supposed to test implementations, not interfaces. So I don't see the problem with testing against an implementation. This is specially true in the cases where you use spy, since you manipulate or verify certain aspects of the implementation. As an aside, imo the principle of always having an interface is of limited value with todays IDEs and other tools. I've quit using interfaces internally in my applications (with a few exceptions), since they don't provide anything in most cases (other than an extra file to keep my javadoc..). – Tobb Apr 28 '16 at 11:18
  • 1
    When you're testing `MyServiceImpl` you of course use the real class you're testing (and you inject mocks into it in places where you don't want to use the real things it depends on). And if you have a `MyServiceImpl2` you also test that, maybe in a different way. Tests belong to some degree inside the encapsulation boundaries of the unit under test. – zapl Apr 28 '16 at 11:28
  • @Tunaki I updated solution 1 by removing the `@Spy` annotation here because I myself am instantiating the implementation there. For solution 2, Mockito will instantiate `MyServiveImpl` for me. I will face the same problem using `@InjectMocks`. I'd like to know which of the 2 suggested solutions would be best to use? – Diyarbakir Apr 28 '16 at 11:29
  • @zapl Thanks for the answer. So I guess I should just forget about the interface here and use the implementation. I think I get it now. – Diyarbakir Apr 28 '16 at 11:33

1 Answers1

0

Thanks for all the responses guys. It helped me a lot. I'll close this question now.

Basically I should test against the Implementation. I also want to reference this question which contains some more useful information.

Community
  • 1
  • 1
Diyarbakir
  • 1,999
  • 18
  • 36