Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it discouraged to use @Spy and @InjectMocks on the same field?

In the project I'm working on right now, I often see the @Spy and @InjectMocks used together on a field. I have never seen it this way in any tutorials or other resources. I googled about this specific combination but didn't find anything else other than this thread on GitHub: https://github.com/mockito/mockito/issues/169

Which makes me think we are using it in a weird way.

Note: The reason why I think using both annotations together makes sense sometimes is because if you only use @InjectMocks Mockito tries to instantiate the class with a no-args constructor. If you don't have a no-args contructor and add @Spy you can use the object without needing an empty constructor.

Edit: Another important use is that you can only stub methods if you just use both annotations.

like image 375
J. Schneider Avatar asked Jul 25 '16 12:07

J. Schneider


People also ask

What is the difference between @InjectMocks and @mock?

@InjectMocks creates an instance of the class and injects the mocks that are created with the @Mock annotations into this instance. @Mock is used to create mocks that are needed to support the testing of the class to be tested. @InjectMocks is used to create class instances that need to be tested in the test class.

What is the difference between mock and spy?

Mocks are used to create fully mock or dummy objects. It is mainly used in large test suites. Spies are used for creating partial or half mock objects. Like mock, spies are also used in large test suites.

What is the use of @InjectMocks annotation?

@InjectMocks is the Mockito Annotation. It allows you to mark a field on which an injection is to be performed. Injection allows you to, Enable shorthand mock and spy injections.

What is Spy in Junit?

A Spy is like a partial mock, which will track the interactions with the object like a mock. Additionally, it allows us to call all the normal methods of the object. Whenever we call a method of the spy object, the real method will be invoked(unless it is stubbed).


1 Answers

It is uncommon, and arguably inappropriate, to use @Spy and @InjectMocks together.

@InjectMocks works as a sort of dependency injection for the system under test: If you have a test that defines a @Mock or @Spy of the right type, Mockito will initialize any fields in your @InjectMocks instance with those fields. This might be handy if you haven't otherwise structured your system-under-test for dependency injection (or if you use a DI framework that does field injection) and you want to replace those dependencies with mocks. It can be pretty fragile—unmatched fields will be silently ignored and will remain null if not set in an initializer—but remains a decent annotation for your system under test.

@Spy, like @Mock, is designed to set up test doubles; you should use it when you have a collaborator that you want to stub or verify. Note there that @Spy and @Mock are always meant for dependencies, and not for your system under test.

Ideally, you should not have any class that fulfills both roles in the same test, or else you may find yourself writing a test that painstakingly tests behavior that you've stubbed rather than actual production behavior. In any case it will be more difficult to tell exactly what the test covers versus the behavior you've stubbed.

Of course, this may not apply if you're trying to use Mockito to test a single method in isolation, and you want to stub calls to one method while testing the other. However, this might also be an indication that your class is violating the Single Responsibility Principle, and that you should break down the class into multiple independent classes that work together. Then, in your test, you can allow instances to have exactly one role and never need both annotations at once.

like image 176
Jeff Bowman Avatar answered Sep 17 '22 00:09

Jeff Bowman