'With InjectMocks, one of my mock become null, without it, an other Mock is null
So in this version, repository is null (and metric is not null) :
@Mock
OperationRepository repository;
@Mock
Metric metric;
SQLStrategy sqlStrategy;
@BeforeEach
public void setup() {
MockitoAnnotations.initMocks(this);
sqlStrategy = new SQLStrategy(metric);
}
In this version, metric is null (and repository is not null) :
@Mock
OperationRepository repository;
@Mock
ReneMetric reneMetric;
@BeforeEach
public void setup() {
MockitoAnnotations.initMocks(this);
}
@InjectMocks
private SQLStrategy sqlStrategy = new SQLStrategy(reneMetric);
This is how they are defined in the class :
@Slf4j
@RequiredArgsConstructor
@Component("sqlDb")
public class SQLStrategy extends StorageStrategy {
@Autowired
private OperationRepository repository;
private final Metric metric;
I was wondering what could be doing this behavior?
I can understand the need for @InjectMocks for repository to not be null since its an @autowired But I really dont understand why metric become null when I use @InjectMocks.
Solution 1:[1]
First of all , @InjectMocks is a Mockito stuff and is nothing to do with Spring. It has no ideas about @Autowired and its existence will not affect @InjectMocks 's behaviour.
Normally you do not need to manually create the instance that you want to inject mocks into. If that instance has non no-arg constructor , Mockito will choose biggest constructors to create instance and inject the mocks through this constructor.
But in case the instance has a no-arg constructor or you instantiate it manually, Mockito will first use property setter injection , and then field injection to inject mocks.
And one caveat is that for the final field , field injection will not happen . You can refer to the docs for more information.
So change to the following should inject both mocks into SQLStrategy :
@ExtendWith(MockitoExtension.class)
public class SQLStrategyTest {
@Mock
OperationRepository repository;
@Mock
ReneMetric reneMetric;
@InjectMocks
private SQLStrategy sqlStrategy;
@Test
public void test(){
}
}
@Slf4j
@RequiredArgsConstructor
@Component("sqlDb")
public class SQLStrategy extends StorageStrategy {
public SQLStrategy(OperationRepository repo , Metric metric){
this.repo = repo;
this.metric = metric;
}
}
And the following explains why your example get such result :
You manually instantiate
SQLStrategy. But at the moment when it is instantiated , Mockito still not create aReneMetricmock , sonew SQLStrategy(null)is called to createSQLStrategyMockito create a mocked instance of
OperationRepositoryandReneMetricSince you manually create
SQLStrategy, Mockito will try to use property setter injection , and then field injection to inject the mocks into it. For theOperationRepository, it is injected because of the field injection. For theMetric, it is not injected because it is a final field andSQLStrategydoes not have any setter for it.So
OperationRepositoryis not null andMetricis null
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Ken Chan |
