How does Mockito handling Suppliers? - java

On the first screenshot you can see my test class. This class is annotated with #ExtendWith({MockitoExtension.class}) and also the tested service is annotated with #InjectMocks. On the second screenshot you can see the tested service.
Why does Mockito uses the long supplier in both cases?

Mockito uses different strategies when injecting mocks in this order:
Constructor injection
Property setter injection
Field injection
Field injection will not work in your example, since the service's fields are declared final.
Since the fields are declared final and the code snippet you showed does not have a field initializer, I assume that you have a constructor with the Supplier args. E.g.
public SomeService(Supplier<String> stringSupplier, Supplier<Long> longTimeSupplier) {
this.stringSupplier = stringSupplier;
this.longTimeSupplier = longTimeSupplier;
}
Thus Mockito will try the constructor injection, find the constructor with the two Supplier parameters and tries to resolve the arguments.
Mockito then finds the two Supplier mocks in the test, but it can not see the generic type due to type erasure. Thus Mockito sees the constructor like this:
public SomeService(Supplier stringSupplier, Supplier longTimeSupplier)
Mockito can also not decide which Supplier to use based on the parameter name, because the normal Java reflection API does not provide that information. So the name of the mocks, will not be taken into account.
There are libraries like paranamer that read the bytecode and extract the debug information to read the parameter names, but Mockito doesn't use that libs.
Thus Mockito just injects the first matching mock which is Supplier<String> stringSupplier in your case. Even your issues is related to generics, Mockito would also act the same way when you have two parameters of the same type that are not generic.
I assumed that you have a constructor that takes the two Supplier. So you can just invoke it in your test's before.
#BeforeEach
public void setup() {
service = new SomeService(stringSupplier, longSupplier);
}
If you can not access the constructor, e.g. it has package scope, you need to invoke it using reflection and set the accessible property to true
#BeforeEach
public void setup() throws Exception {
Constructor<SomeService> constructor = SomeService.class.getConstructor(Supplier.class, Supplier.class);
constructor.setAccessible(true);
service = constructor.newInstance(stringSupplier, longSupplier);
}
PS If you want to remove the final, make sure that the mocks are either named after the fields in the service longTimeSupplier vs. longSupplier or you use #Mock(name = "longTimeSupplier").

Related

Getting NullPointerException in my mock dependence

I have this test:
#RunWith(MockitoJUnitRunner.class)
public class MainClassTest {
#Mock
Dependence dependence;
#InjectMocks
MainClass mainClassTester;
}
And this test:
#Test
public void testA() {
when(dependence.getStatus()).thenReturn(true);
mainClassTester.startStatusOperation();
}
My MainClass class looks like:
public class MainClass{
private Dependence dependence = new Dependence() ;
public boolean startStatusOperation(){
boolean status = dependence.getStatus();
[...]
}
}
Im getting NullPointer in this line:
boolean status = dependence.getStatus();
Why doesn't the mock "dependence" work? This code always worked when I used #inject, but can't use in this one.
If you want to use constructor to create object instead of #Inject, you need to mock the constructor instead of just using #Mock.
#InjectMock will only inject the field which you use by #Inject. If you have any field which is set by new constructor, this will be not injected in test object if you use #InjectMock.
From http://site.mockito.org/mockito/docs/current/org/mockito/InjectMocks.html
#Documented
#Target(value=FIELD)
#Retention(value=RUNTIME)
public #interface InjectMocks
Mark a field on which injection should be performed.
Allows shorthand mock and spy injection.
Minimizes repetitive mock and spy injection.
Mockito will try to inject mocks only either by constructor injection, setter injection, or property injection in order and as described below. If any of the following strategy fail, then Mockito won't report failure; i.e. you will have to provide dependencies yourself.
Constructor injection; the biggest constructor is chosen, then arguments are resolved with mocks declared in the test only. If the object is successfully created with the constructor, then Mockito won't try the other strategies. Mockito has decided to no corrupt an object if it has a parametered constructor.
Note: If arguments can not be found, then null is passed. If non-mockable types are wanted, then constructor injection won't happen. In these cases, you will have to satisfy dependencies yourself.
Property setter injection; mocks will first be resolved by type (if a single type match injection will happen regardless of the name), then, if there is several property of the same type, by the match of the property name and the mock name.
Note 1: If you have properties with the same type (or same erasure), it's better to name all #Mock annotated fields with the matching properties, otherwise Mockito might get confused and injection won't happen.
Note 2: If #InjectMocks instance wasn't initialized before and have a no-arg constructor, then it will be initialized with this constructor.
Field injection; mocks will first be resolved by type (if a single type match injection will happen regardless of the name), then, if there is several property of the same type, by the match of the field name and the mock name.
Note 1: If you have fields with the same type (or same erasure), it's better to name all #Mock annotated fields with the matching fields, otherwise Mockito might get confused and injection won't happen.
Note 2: If #InjectMocks instance wasn't initialized before and have a no-arg constructor, then it will be initialized with this constructor.

Dagger 2: When to use constructor injections and when to use field injections?

I was kind of lazy and used to use almost entirely field injections. I was just providing empty constructor, put my #Inject fields I everything was looking nice and simple. However field injection have its trade-offs so I've devised some simple rules that help me to decide when to used field and when to use constructor injections. I will appreciate any feedback if there is mistake in my logic or if you have additional considerations to add.
First some clarification in order to be on the same page:
Constructor injection:
#Inject
public SomeClass(#Named("app version") String appVersion,
AppPrefs appPrefs) {...
Same with the field injection:
public class SomeClass {
#Inject
#Named("app version") String mAppVersion;
#Inject
AppPrefs appPrefs;
Rule 1: MUST use field injection if I don't control creation of the object (think Activity or Fragment in Android). If some (non-dagger aware) framework is creating my object and handles it to me I have no choice but to inject it manually after I receive the instance.
Rule 2: MUST use constructor injection if the class is/may be used in another project that does not use Dagger 2. If the other project(s) do not use Dagger they cannot use DI so the user have to create the object the "old" way using new.
Rule 3: PREFER constructor injection when working with class hierarchies because it is easier to create unit tests.
Clarification:
Considering the following structure that uses field injection:
package superclass;
public class SuperClass {
#Inject
HttpClient mHttpClient;
...
}
.
package differentpackage;
public class SubClass extends SuperClass {
public SubClass() {
}
}
When I am creating unit test for SubClass in directory test/java/differentpackage I have no choice but to bring up the entire DI infrastructure in order to be able to inject the HttpClient. In contrast, if I was using constructor injection like this:
public class SuperClass {
private final HttpClient mHttpClient;
#Inject
public SuperClass(HttpClient httpClient) {
mHttpClient = httpClient;
}
}
in my unit test I could simply:
HttpClient mockHttp = mock(HttpClient.class);
Subclass tested = new Subclass(mockHttp);
// tests
So basically now I am in the other extreme: I tend to rely mostly on constructor injections and use field injections only when 'Rule 1' applies.
The only 'problem' that I have with the constructor injects is that for 'end' classes constructors sometimes become quite overloaded with parameters and they look verbose and ugly like this:
#Inject
public ModelMainImpl(#Named("app version") String appVersion,
AppPrefs appPrefs,
LoginPrefs loginPrefs,
#ForApplication Context appContext,
NetworkInfoProvider networkInfoProvider,
AndroidEventPoster androidEventPoster,
Session session,
ForgeExchangeManager exchangeManager,
HttpFunctionality httpFunctionality,
#Named("base url") String baseUrl,
#Named("forge result producer") ResultProducer<ForgeExchangeResult> resultProducer
) {
Guys, what are your rules to choose between constructor and field injects? I am missing something, are there errors in my logic?
Use constructor injection. if you can't, use property injection.
Rule 1 seems ok, like decorations or attributes you can use Property(field) injection.
Rule 2 seems ok, because who uses your class they have to follow your constructor. They may not know they have to intilaize your property also.
Rule 3 It's not just good for unit test. It's good for applying Single Responsibilty. It's easier to see your object graph.Otherwise you will hide it with property.
If we come in your question, yes there a lot of parameters in your constructor. But the solution is not property injection. You can refactor your code and use aggregate services

Writing testable code when new object is being constructed using Mockito only

So I am writing a class which I want to follow the best practices and be testable.
I have a new object to be created inside it. So, I am following the factory pattern to achieve it.
public class Apple {
// factory object injected in class
private SeedFactory seedFactory;
// Method to be tested
public void myMethod(String property1, int property2, String depends) {
// Just to set the necessary parameter
seedFactory = new SeedFactory(property1, property2);
// Factory pattern intact. Instance generation depends on only one parameter
SeedFactory result = seedFactory.getInstance(depends);
}
}
EDIT: Adding code for factory as well.
public class SeedFactory{
String property1;
int property2;
SeedFactory(property1,property2){
this.property1 = property1;
this.property2 = property2;
}
SeedFactory getInstance(int depends){
if(depends == 1)
{ // do stuff }
else{ // do stuff and return instance }
Now, before I actually create the new object, I have to make sure that I set two properties for the new instance to be generated, which are needed to be present irrespective of the type of instance generated by the factory. depends is the actual parameter which tells the factory what instance to return.
Now, as far as testability of this code is concerned, I can user PowerMockito to mock the factory object using whenNew but using PowerMockito is not a choice. I have to make it testable without it.
Also, I have tried to encapsulate the new call within a one line function and then use spy. But I want to avoid using spy, since it is not considered a good practice, in context of where this code is being used as a whole.
So my question is, Is there any way, without using PowerMockito, to re-write this class so that it can be unit tested properly?
If the instance to be generated needed only one parameter, then it would have been trivial. However, I don't want to pass more than one parameter to getInstance().
SeedFactory is not Apple's dependancy but your method depends on SeedFactory which has "uses" relationship. So to define proper relation i would suggest you use "USES" relation as below:
public void myMethod(SeedFactory seedFactory, String depends){ // Method to be tested
Now you could mock SeedFactory and can unit test it appropriately.
I think you're doing something wrong.
If SeedFactory isn't an Apple's dependency but an internal concern, hence you don't need to mock a SeedFactory to test Apple. You should test the public API provided by Apple only.
If SeedFactory is an Apple's dependency, so it definitely should be injected.

How to annotate injector.getInstance?

I want to inject an instance from Guice injector in my unitTest.
Which diffrentiator can I use?
I know #annotation mechanism is used in ctor params
but junit doesn't allow ctor with params.
should I use class fields' #annotation?
public void setUp() throws Exception {
RoutingResponseRepository routingResponseRepository = injector.getInstance(RoutingResponseRepository.class);
}
e.g.
I want
#firstType RoutingResponseRepository
and
#secondType RoutingResponseRepository
For testing, you could just inject into your test-case-instance. Then you can use your injection-points just as you would in production code:
#Inject
#SecondType
private RoutingResponseRepository;
#Before
public void setUp() {
Guice.createInjector().injectMembers(this);
}
without caring about Types and Keys.
Use Injector.getInstance(Key):
injector.getInstance(Key.get(RoutingResponseRepository.class, firstType.class))
When referring to a binding, Guice internally uses an immutable Key instance, which refers to an annotation status (a binding annotation class, a binding annotation instance, or no binding annotation) combined with a type (a class literal, a Type instance, or a TypeLiteral). Matching this matrix, there are 9 different overloads of Key.get, which is the static factory method to get these Key objects. Overloads that take Class<?> are offered just for the sake of convenience.
In general, any time you want to represent a parameterized or annotated type (like in getInstance or bind), you can use an overload that takes a Key instead.

Mocking an abstract class with a mocked constructor argument?

I'd like to use Mockito to unit test an abstract class as detailed in this great answer.
The trick is, the abstract class has a dependency on a strategy that gets injected in its constructor. I've created a mock of the strategy and I'd like for my mocked instance of BaseClass to use the mocked strategy for my unit test.
Any suggestion as to how I can wire this up? I'm not currently using any IoC framework, but am considering Spring. Perhaps it would do the trick?
// abstract class to be tested w/ mock instance
abstract BaseClass
{
// Strategy gets mocked too
protected BaseClass( Strategy strategy)
{
...
}
}
Update:
According to the Mockito mailing list, there currently isn't a way to pass arguments to the constructor of a mock.
I ended up just using reflection to set a private field in my base class, like so:
// mock the strategy dependency
Strategy strategyMock = mock( Strategy.class);
when(....).thenReturn(...);
// mock the abstract base class
BaseClass baseMock = mock(BaseClass.class, CALLS_REAL_METHODS);
// get the private streategy field
Field strategyField = baseMock.getClass().getSuperclass().getDeclaredField("_privateStrategy");
// make remove final modifier and make field accessible
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(strategyField, strategyField.getModifiers() & ~Modifier.FINAL);
strategyField.setAccessible(true);
// set the strategy
strategyField.set(baseMock, strategyMock);
// do unit tests with baseMock
...
It would break if the name of the private field ever changed, but its commented and I can live with that. It's simple, it;s one line of code and I find this preferable to exposing any setters or having to explicitly subclass in my tests.
Edit: So it's not one line of code anymore since my private field needed to be 'final', requiring a some extra reflection code to get around.
Ive seen this sort of thing done using Mockito at a spring context level.
eg:
<bean id="myStrategy" name="myStrategy" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="Strategy" />
</bean>
I hope that helps.
You don't need to do anything special. Just mock the bean like normal:
Bean bean = mock(Bean.class);
when(bean.process()).thenReturn(somethingThatShouldBeNamedVO);
Just works :)

Categories