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.
Related
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").
While reviewing some code I have noticed a POJO (without scope -> #Dependant) which is injected (#Inject) in another bean and that do inject a bean (a field).
But it has also an #Inject annotation on a no-args public method that does initialisations stuff. I thought injection points only happen on field, constructor and setter
public class MyImpl implements MyInterface {
#Inject
private ParamDao paramDao;
private Map<String,List<MyRateDto>> params;
#Inject
public void loadRates() {
params = paramDao....;
}
...
}
To me this method (loadRates) should have been annotated as #PostConstruct. But I was wondering what happen in such case?
I guess the method is simply called after bean creation and field injection... But I have not read anything about it in the spec or elsewhere.
Is it the expected behavior?
Environment: Java 8/JavaEE 7 that targets a JBoss EAP 7.
Thanks
Thanks to #Andreas I have been steered in the right direction.
Looking at the Javadoc of #Inject: "Constructors are injected first, followed by fields, and then methods. Fields and methods in superclasses are injected before those in subclasses. Ordering of injection among fields and among methods in the same class is not specified. --- Injectable methods [...] accept zero or more dependencies as arguments."
So, there is no explicit description for zero arguments. But it's just that #Inject methods are called in arbitrary order, and arguments are resolved.
No argument = nothing to resolve.
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
I have a class that I mocked like this:
#Mock
private MyClass1 mockMyClass1;
Say this class looks like that:
public class MyClass1 {
#Autowired
private MyInnerClass myInnerClass;
}
When I mock MyClass1, MyInnerClass will be initialized as null. Is it possible to initialize that private field with another mock objected? I want myInnerClass to be a mock like this one:
#Mock
private MyInnerClass myInnerClass;
If I use the following code:
#InjectMocks
private MyClass1 mockMyClass1;
#Mock
private MyInnerClass myInnerClass
This will initialize the private MyInnerClass inside MyClass1 to be the mocked object, however this way mockMyClass1 is not a mock itself any more, isn't it (I'm only injecting a mocked object inside a real class, just like #Autowired will inject a real object insite it)? Could you correct my logic if I'm wrong in my understanding of #InjectMock and #Mock? Also how could I inject a mocked object inside another mocked object (without using setters/constructors)?
You are misunderstanding what a mock is.
When you are mocking MyClass1, the inner field of type MyInnerClass doesn't exist anymore for the mocked object. As such, it doesn't make sense to try to inject something into a mock.
A mock is controlled by saying what it should do when you interact with it. You stub its public methods to do what you want them to do. You give behaviour. The only default behaviour (maybe specific to Mockito) is to return null if you didn't configure the mock (but do note that it doesn't return null because some internal variable is null, it returns that because Mockito decided that that's what it should return; maybe another mocking framework decided that it should throw an exception instead, who knows?).
As an example, consider that your real class is:
class MyClass1 {
private MyInnerClass myInnerClass;
public MyInnerClass getMyInnerClass() {
return myInnerClass;
}
}
Now consider mock a mock of that class. If you call mock.getMyInnerClass(), it is not the real method that is going to be called. What it will return is not the value of myInnerClass. It will return null, or if you have stubbed that method with
when(mock.getMyInnerClass()).thenReturn(something);
then it will return something.
So to answer your question: you can't do that because that's not how mocks work.
You shouldn't really use InjectMocks annotation at all (to see why, you can read this article).
You could just implement an Autowired constructor for MyClass1 instead of Autowired fields. Then you could simply pass your MyInnerClass mock reference as a constructor parameter.
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 :)