I'm trying to inject a mock for a unit test but I keep getting a null point exception.
The class I'm trying to test is below, the null pointer seems to be with the ParameterFacade.
When I run the test it doesn't seem to be injecting the mock as the ParameterFacade is null.
#Service
public class PostUnderwriterTransactionProcessProvider extends AbstractProcessProvider<PostUnderwriterTransactionInput> {
#Autowired
private ParameterFacade parameterService;
#Override
public Page startProcess(PostUnderwriterTransactionInput processInput) {
final PostUnderwriterTransactionContext context = new PostUnderwriterTransactionContext(processInput.getPolicy(),
setupStrataContextModel(POST_TRANSACTIONS),
processInput.getTransactionsTypes(),
processInput.getParameterSelectionCriteria(),
parameterService.shouldApplyCommissionFromPolicy());
context.setPostingFromInput(processInput.getAccount().getBalance(),
processInput.getAccount().getID(),
getBranch(),
processInput.getPolicy(),
processInput.getProcess(),
null);
return new AdhocTransactionPostingPage(new TransactionPostingContextModel(context));
}
}
The test is
#RunWith(MockitoJUnitRunner.class)
public class PostUnderwriterTransactionProcessProviderTest extends WicketTestCase {
#ClassRule
public static MetadataServiceRule metadataServiceRule = new MetadataServiceRule();
#Mock
private ParameterFacade mockParameterService;
#InjectMocks
private PostUnderwriterTransactionProcessProvider testSubject;
#Before
public void setup() {
tester.putBean(mockConversationScopeManager);
testSubject = new PostUnderwriterTransactionProcessProvider();
policy = PolicyTestDataBuilder.aPolicy().build();
account = createAccount();
testSubject.setUserInfoProvider(MockUserInfoPartyProvider.getMockUserInfoProvider());
testSubject.setSystemPartyFacade(MockUserInfoPartyProvider.getMockSystemPartyFacade());
testSubject.setCodeModelFacade(codeModelFacade);
}
#Test
public void startProcessShouldCreateAdhocTransactionPostingPage() {
// Given
when(mockParameterService.shouldApplyCommissionFromPolicy()).thenReturn(true);
final ParameterSelectionCriteriaModel pscm = new ParameterSelectionCriteriaModel();
final List<TransactionTypeModel> transactions = createTransactionsTypes();
final PostUnderwriterTransactionInput input = new PostUnderwriterTransactionInput(policy, account, pscm, transactions);
// When
final Page page = testSubject.startProcess(input);
// Then
assertThat(page, instanceOf(AdhocTransactionPostingPage.class));
assertThat("Page Default Model is: ", page.getDefaultModelObject(), instanceOf(PostUnderwriterTransactionContext.class));
assertPageContextValues(page);
}
}
1. ParameterFacade is a spring container managed bean (as it is annotated with #Service and other spring annotations like #Autowired).
2. #RunWith is configured to use MockitoJUnitRunner which cannot instantiate spring managed container beans
Hence, in order to handle bean lifecycle in unit tests you'll need to
1. Use #RunWith(SpringJUnit4ClassRunner.class)
2. Annotate PostUnderwriterTransactionProcessProvider with #Autowired.
3. Change #Mock to #MockBean on ParameterFacade (org.springframework.boot.test.mock.mockito.MockBean)
Take a look at you following code, let's see what each line does -
#Mock
private ParameterFacade mockParameterService; //1
#InjectMocks
private PostUnderwriterTransactionProcessProvider testSubject; // 2
#Before
public void setup() {
testSubject = new PostUnderwriterTransactionProcessProvider(); //3
}
Line 1 uses spring framework's #Mock annotation. This tells spring to mock an object of type ParameterFacade, create a mocked instance and hold it in the mockParameterService variable
Line 2 uses the #InjectMocks annotation, which tell spring to use the mocked object created in this test (which we created in line 1) and use it as a dependency in the variable testSubject when creating it. This will result in testSubject containing an instance of PostUnderwriterTransactionProcessProvider that has a dependency of a mocked type ParameterFacade injected to him
Line 3 creates a new instance of PostUnderwriterTransactionProcessProvider. this is pure java, no spring, no mocks, no dependencies. Simply create a new instance of that type the regular way java would do that. The instance that was created in 2 is replaced by this new plain instance and , in a way any assertion will override a previous value, which leaves the variable testSubject holding this object
The line
testSubject = new PostUnderwriterTransactionProcessProvider();
is overriding the instance created with
#InjectMocks
private PostUnderwriterTransactionProcessProvider testSubject;
Remove the manual initialization to let the framework behave as designed.
Otherwise, if you want to be able to manually inject the dependency then consider refactoring the class to follow Explicit Dependency Principle
#Service
public class PostUnderwriterTransactionProcessProvider
extends AbstractProcessProvider<PostUnderwriterTransactionInput> {
private final ParameterFacade parameterService;
#Autowired
public PostUnderwriterTransactionProcessProvider(ParameterFacade parameterService) {
this.parameterService = parameterService;
}
//...omitted for brevity
}
This can allow more flexibility when creating the subject
#RunWith(MockitoJUnitRunner.class)
public class PostUnderwriterTransactionProcessProviderTest extends WicketTestCase {
#ClassRule
public static MetadataServiceRule metadataServiceRule = new MetadataServiceRule();
#Mock
private ParameterFacade mockParameterService;
private PostUnderwriterTransactionProcessProvider testSubject;
#Before
public void setup() {
tester.putBean(mockConversationScopeManager);
testSubject = new PostUnderwriterTransactionProcessProvider(mockParameterService);
//...omitted for brevity
Related
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.
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 a ReneMetric mock , so new SQLStrategy(null) is called to create SQLStrategy
Mockito create a mocked instance of OperationRepository and ReneMetric
Since you manually create SQLStrategy , Mockito will try to use property setter injection , and then field injection to inject the mocks into it. For the OperationRepository , it is injected because of the field injection. For the Metric , it is not injected because it is a final field and SQLStrategy does not have any setter for it.
So OperationRepository is not null and Metric is null
I have a Service A which autowired Service B and is using a method from Service B.
Service B autowired another Service C and is using a method from it.
I am writing a test for Service A and the test fails at the call where Service B is invoked.At this point Service C is null.
I have tried #Mock for Service B. Nothing seems to work. How can i successfully test this service which is failing on a service that it isnt explicitly autowiring.
//Service A
#Service
public class FileServiceImpl{
#Autowired
private FileNameServiceImpl fileNameService;
public void createFile(String fileName){
String targetFileName = fileNameService.getTargetFileName(fileName);
}
}
//Service B
#Service
public class FileNameServiceImpl{
#Autowired
private CustomDateService customDateService
public String getTargetFileName(String fileName){
return fileName + customDateService.getCustomDate();
}
}
//CustomDate - this is an interace. The Impl is in another package.
public interfaceCustomDateService{
public String getCustomDate();
}
I am trying to test FileServiceImpl , however it fails with a NullPointer Exception because customDateService is null.
Even though, FileServiceImpl is not calling customDateService.
This is what I have for test thus far:
#Category(UnitTest.class)
#RunWith(MockitoJUnitRunner.class)
public class FileServiceImplTest {
#Spy
#InjectMocks
private FileServiceImpl fileServiceImpl;
#Mock
private FileNameServiceImpl fileNameService;
#Before
public void init() throws Exception {
MockitoAnnotations.initMocks(this);
}
#Test
public void testFileName() {
String fileName = "test1.txt";
fileServiceImpl.createFile(fileName); // Test Fails here
Mockito.validateMockitoUsage();
}
As Shane eluded, this sounds like you're maybe integration testing.
If so, make sure the context of your test encompasses the autowired components.
You should post some code, as it's hard to know what exactly is going on here.
If you aren't integration testing, don't rely on autowiring, just construct new ServiceA manually passing in a mocked ServiceB.
Also make sure to initialise your mocks.
private ServiceA serviceA;
#Mock
private ServiceB serviceB;
#BeforeEach
public void setUp() {
MockitoAnnotations.initMocks();
serviceA = new ServiceA(serviceB);
}
EDIT:
First of all, as good practice you should favor constructor injection over field injection in Spring.
So set up the service classes with Autowired constructors.
Also, I'm pretty sure with a mockito Spy you have to initialise the class.
If you switch to use constructor Autowiring you can inject the mocks manually.
#Category(UnitTest.class)
#RunWith(MockitoJUnitRunner.class)
public class FileServiceImplTest {
#Spy
private FileServiceImpl fileServiceImpl;
#Mock
private FileNameServiceImpl fileNameService;
#Before
public void init() throws Exception {
MockitoAnnotations.initMocks(this);
fileServiceImpl = new FileServiceImpl(fileNameService);
}
#Test
public void testFileName() {
String fileName = "test1.txt";
fileServiceImpl.createFile(fileName); <-- now this shouldn't fail
Mockito.validateMockitoUsage();
}
i have a java spring service that call a spring data repository and i want to do a Junit test with mockito , this is my class and the service that i want to test :
#Service
public class DataServiceImpl implements DataService{
#Autowired
private CautionRepository cautionRepository;
#Override
public void addCautions(List<CautionsDTO> cautions, Contrat contrat) {
if(cautions != null && !cautions.isEmpty()) {
cautions.forEach(caution -> {
Caution caution = new Caution();
cautionContrat.setAmount(caution.getAmount());
cautionContrat.setDate(caution.getDate());
caution.setContrat(contrat);
cautionRepository.save(caution);
});
}
}
}
and this is my Unit test
#RunWith(SpringRunner.class)
public class DataServiceImplTest{
#InjectMocks
private DataServiceImpl dataService;
#Mock
private CautionRepository cautionRepository;
#Test
public void addListCautionsTest() {
List<CautionsDTO> cautions = new ArrayList<>();
ContratExportation contrat = new ContratExportation();
Caution caution = new Caution();
dataDelService.addCautions(cautions,contrat);
Mockito.verify(cautionRepository, times(1)).save(caution);
}
}
When i run the test i got the folowwing error :
Wanted but not invoked:
cautionRepository.save(
org.model.Caution#2abe9173
);
-> at org.service.DataServiceImplTest.addListCautionsTest(DataServiceImplTest.java:292)
Actually, there were zero interactions with this mock.
Do you have any idea please what is the mistake with my test
You never add a value to cautions so the loop is not executed and verify must fail.
Add a value to the list and the test should pass:
List<CautionsDTO> cautions = new ArrayList<>();
ContratExportation contrat = new ContratExportation();
CautionDTO caution = new CautionDTO();
cautions.add(caution);
dataDelService.addCautions(cautions,contrat);
This should be the correct code for executing the test
#RunWith(SpringRunner.class)
public class DataServiceImplTest{
#Autowired
private DataServiceImpl dataService;
#MockBean
private CautionRepository cautionRepository;
#Test
public void addListCautionsTest() {
List<CautionsDTO> cautions = new ArrayList<>();
ContratExportation contrat = new ContratExportation();
Caution caution = new Caution();
dataDelService.addCautions(cautions,contrat);
Mockito.verify(cautionRepository, times(1)).save(caution);
}
}
First of all, you forgot to add caution object into cautions list. But other than that you are mixing Unit test with Integration test.
You need to annotate your test class with #RunWith(MockitoJUnitRunner.class),
or
You need to annotate your mock objects with #MockBean and add #Autowired to your test class DataServiceImpl object.
Now, let me explain to you.
Unit Test
When you want to write a unit test, you should not make use of application context (autowiring).
By the way, a better approach is to annotate your DataServiceImpl with #RequiredArgsConstructor from Lombok and remove #Autowired from CautionRepository. This will allow you to instantiate DataServiceImpl in a setup method in your unit test.
Your DataServiceImpl class should be:
#Service
#RequiredArgsConstructor
public class DataServiceImpl implements DataService{
private final CautionRepository cautionRepository;
#Override
public void addCautions(List<CautionsDTO> cautions, Contrat contrat) {
// your code...
}
}
and your new unit test class:
#RunWith(MockitoJUnitRunner.class)
public class DataServiceImplTest{
private DataServiceImpl dataService;
#Mock
private CautionRepository cautionRepository;
#Before
public void setup() {
dataService = new DataServiceImpl(cautionsRepository);
}
#Test
public void addListCautionsTest() {
// your test code...
}
}
Integration Test
Now, if you want to create an integration test, use #RunWith(SpringRunner.class). By doing this your application context will be loaded. In your case you can create a mocked bean inside your context by annotating your object with #MockBean. This will inject mocked object into your context and it will get auto wired in your real class.
For this your new DataServiceImpl class can remain same as above. But change your integration test into:
#RunWith(SpringRunner.class)
public class DataServiceImplTest{
#Autowired
private DataServiceImpl dataService;
#MockBean // it will be injected automatically
private CautionRepository cautionRepository;
#Test
public void addListCautionsTest() {
// your test code...
}
}
Hope, you now understand the difference and the mistake you were doing :)
I got 2 modules User and Email, both of them have 1 entry point which is a facade, rest is package scoped. The configuration is done in 2 classes
#Configuration
class UserConfiguration {
#Bean
UserFacade userFacade(UserRepository repository, EmailFacade emailFacade) {
return new UserFacade(repository, emailFacade);
}
}
#Configuration
class EmailConfiguration {
#Bean
EmailFacade emailFacade(EmailSender emailSender) {
return new EmailFacade(emailSender);
}
}
Now, I want to write tests that don't require Spring to start. I implemented a simple InMemoryRepository to make this happen
#RunWith(MockitoJUnitRunner.class)
public class RegisterUserTest {
#Mock
private EmailFacade emailFacade = new EmailFacade(new FakeEmailSender());
#InjectMocks
private UserFacade userFacade = new UserConfiguration().userFacade(new InMemoryUserRepository(), emailFacade);
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
}
I need some fake objects to instantiate EmailFacade so I wrote fake implementation
public class FakeEmailSender implements EmailSender {
#Override
public void sendEmail(EmailMessage emailMessage) throws RuntimeException {
}
}
In that scenario, I'm testing User domain, so I want to mock Email anyways.
I wrote a test to check if it works
#Test
public void shouldReturnSendingFailed() {
Mockito.when(emailFacade.sendUserVerificationEmail(Mockito.any())).thenReturn(Either.left(EmailError.SENDING_FAILED));
assertThat(userFacade.registerNewUser(RegisterUserDto.builder()
.username(USERNAME_4)
.email(VALID_EMAIL)
.password(VALID_PASSWORD).build()).getLeft(), is(EmailError.SENDING_FAILED));
}
But it isn't... after running this test I got
java.util.NoSuchElementException: getLeft() on Right
edit#
regiserNewUser() method
Either<DomainError, SuccessMessage> register(RegisterUserDto registerUserDto) {
if(userRepository.findUser(registerUserDto.getUsername()).isPresent())
return Either.left(UserError.USERNAME_ALREADY_EXISTS);
var userCreationResult = User.createUser(registerUserDto);
var savedUser = userCreationResult.map(this::saveUser);
var emailDto = savedUser.map(this::createVerificationEmail);
return emailDto.isRight() ? emailFacade.sendUserVerificationEmail(emailDto.get())
: Either.left(emailDto.getLeft());
}
Edit2#
With following test configuration
#RunWith(MockitoJUnitRunner.class)
public class RegisterUserTest {
#Mock
private EmailFacade emailFacade;
#InjectMocks
private UserFacade userFacade = new UserConfiguration().userFacade(new InMemoryUserRepository(), emailFacade);
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
}
I got nullpointer here, last line of registerNewUser().
Try running this code
#RunWith(MockitoJUnitRunner.class)
public class RegisterUserTest {
#Mock
private EmailFacade emailFacade;
private UserFacade userFacade;
#Before
public void setUp() {
userFacade = new UserConfiguration().userFacade(new InMemoryUserRepository(), emailFacade);
}
}
There are a few issues with your code:
You initialize your mocks twice. You don’t need to call initMocks in the setUp method if you are using Mockito runner
You are trying to inject mocks to already initialized object. But the field you are trying to inject is also passed to the constructor. Please read #InjectMocks doc, to check the strategies used to inject the mocks:
constructor (not used here, already initialized object)
setter (do you have one?)
field (is it not final)
There are details to each strategy (see my questions above). If no staregy is matched, Mockito will fail silently. The fact that you are passing an object in constructor, and rely on setter or field injection afterwards makes this code unnecesarily complex.
I have a JUnit test that reads
public class EventHandlerTest {
#Mock
ThreadPoolExtendedExecutor threadPoolExtendedExecutor;
private EventHandler handler;
private Map<Queue<SenderTask>> subBuffers = new HashMap<>();
#Before
public void setUp() {
// PROBLEM: threadPoolExtendedExecutor null!
handler = new EventHandler(subBuffers, threadPoolExtendedExecutor);
}
}
When I call new in setUp, I have threadPoolExtendedExecutor=null.
I would like to insert some mocked threadPoolExtendedExecutor so, I do not have NullPointer problems when calling its methods (so simple interface mock is enough for me at this moment)
You can simply mock it using (in setUp)
threadPoolExtendedExecutor = mock(ThreadPoolExtendedExecutor.class);
#Before
public void setUp() {
threadPoolExtendedExecutor = mock(ThreadPoolExtendedExecutor.class);
handler = new EventHandler(subBuffers, threadPoolExtendedExecutor);
}
You can also let MockitoJUnitRunner do it for you :
don't forget to inject mocks in your service under test by annotating it with #InjectMocks
#RunWith(MockitoJUnitRunner.class)
public class EventHandlerTest {
#Mock
ThreadPoolExtendedExecutor threadPoolExtendedExecutor;
If you would like to use the #Mock or #InjectMocks annotations on the test class fields then you need to add #RunWith(MockitoJUnitRunner.class) at the class level.
#RunWith(MockitoJUnitRunner.class)
public class EventHandlerTest {
#Mock
ThreadPoolExtendedExecutor threadPoolExtendedExecutor;
Another approach is to not use the above annotations and manually create mocks by calling org.mockito.Mockito.mock().