Use Mocked object in JUnit / Mockito test - java

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().

Related

Mocking of same type getting overridden in junit

Test case code ->
#RunWith(MockitoJUnitRunner.class)
public class AzureTopicPublisherTest {
#Mock
#Qualifier("ackPublisherv1")
AckPublisher ackPublisherv1;
#Mock
#Qualifier("ackPublisherv2")
AckPublisher ackPublisherv2;
Source code ->
private final AckPublisher ackPublisherv1;
private final AckPublisher ackPublisherv2;
public void test()
{
ackPublisherv1.publishToTopic(response);
ackPublisherv2.publishToTopic(response);
}
Mocks which are not working ->
verify(ackPublisherv1, times(1)).publishToTopic(anyString());
verify(ackPublisherv2, times(1)).publishToTopic(anyString());
Issue is I observed one of the instance getting called twice.
There is different mock for ackPublisherv1 and ackPublisherv2
when i debug this code then i can see same instance twice in source code.
if I write above mock as follows then its working but that is not expected behavior ->
verify(ackPublisherv2, times(2)).publishToTopic(anyString());
I tried removing qualifier annotations as well. still same error.
As far as I know #InjectMocks doesn't support #Qualifiers.
Instantiate the class you have the test method in a setup method.
#Mock
AckPublisher ackPublisherv1;
#Mock
AckPublisher ackPublisherv2;
SourceClass underTest;
#Before
public void setUp() throws Exception {
underTest = new SourceClass(ackPublisherv1, ackPublisherv2);
}

How to Test void Method with spring repository using Junit and Mockito

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 :)

Nullpointer when using Mockito for unit tests

I am creating a spring boot API for my application. I am attempting to unit test my service implementation using mockito to mock out the detail. The service will add a new building entity to the database. Below is the Service implementation and the test implementation.
Building Service:
#Slf4j
#Service
public class BuildingServiceImpl implements BuildingService {
private BuildingRepository buildingRepository;
private BuildingRequestToEntityMapper buildingRequestToEntityMapper;
public BuildingServiceImpl(BuildingRepository buildingRepository, BuildingRequestToEntityMapper
buildingRequestToEntityMapper){
this.buildingRepository=buildingRepository;
this.buildingRequestToEntityMapper=buildingRequestToEntityMapper;
}
public HttpStatus addBuilding(BuildingRequest buildingRequest){
log.info("Inside addBuilding() service");
BuildingEntity buildingEntity = buildingRequestToEntityMapper.map(buildingRequest);
buildingRepository.save(buildingEntity);
log.info("Building saved "+ buildingEntity);
return HttpStatus.CREATED;
}
BuildingServiceImpl_UT
#RunWith(MockitoJUnitRunner.class)
public class BuildingServiceImpl_UT {
#Mock
BuildingRequestToEntityMapper buildingRequestToEntityMapper;
#Mock
BuildingRepository buildingRepository;
#InjectMocks
BuildingServiceImpl buildingServiceImpl;
#Test
public void buildingService_MapsRequest_AndSaveEntity(){
BuildingRequest buildingRequest = BuildingRequest.builder()
.name("TestName")
.telephone("4444444444")
.postcode("TEst")
.address("testAddress").build();
when(buildingServiceImpl.addBuilding(any(BuildingRequest.class))).thenReturn(HttpStatus.CREATED);
when(buildingRepository.save(any(BuildingEntity.class))).thenReturn(new BuildingEntity());
buildingServiceImpl.addBuilding(buildingRequest);
verify(buildingRepository, times(1)).save(any());
}
I have mocked the mapper and repository and injected them into the service, but when i run the test I get a null pointer exception at the first when().thenReturn() statement in the test class. Any help please. Thanks
I don't understand your first when().thenReturn()! You try to do this on the buildingServiceImpl wich is not a mock! Further more this makes no sense because you want to test this methode!
I think you should define a when().thenReturn() for the mock buildingRequestToEntityMapper, but in your implementation you don't need to define a return for buildingRequestToEntityMapper.map(). In this case the variable buildingEntity will have the value null which should work in your test case.
#RunWith(MockitoJUnitRunner.class)
public class BuildingServiceImpl_UT {
#Mock
BuildingRequestToEntityMapper buildingRequestToEntityMapper;
#Mock
BuildingRepository buildingRepository;
#InjectMocks
BuildingServiceImpl buildingServiceImpl;
#Test
public void buildingService_MapsRequest_AndSaveEntity(){
BuildingRequest buildingRequest = BuildingRequest.builder()
.name("TestName")
.telephone("4444444444")
.postcode("TEst")
.address("testAddress").build();
when(buildingRepository.save(any(BuildingEntity.class))).thenReturn(new BuildingEntity());
buildingServiceImpl.addBuilding(buildingRequest);
verify(buildingRepository, times(1)).save(any());
verify(buildingRequestToEntityMapper).map(any());
}
This:
when(buildingServiceImpl.addBuilding(any(BuildingRequest.class))).thenReturn(HttpStatus.CREATED);
is not necessary, you want to test method: addBuilding not mock it.

Mock not being Injected

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

Mockito - how to inject final field marked as #Mock by constructor when using #Spy and #InjectMocks

I have a special case, where I have to mock some fields and use both #Mock and #Spy for my class, which is under test, because at some tests I need to change behaviour of it's own methods. I use #InjectMocks for constructor. It looks like this:
Test class:
#RunWith(MockitoJUnitRunner.class)
public class ServiceTest {
#Mock
private SomeObject usedAsNonFinal;
#Mock
private SomeObject usedAsFinal;
#Spy
#InjectMocks
private ServiceTest service = new ServiceTest(usedAsNonFinal, usedAsFinal);
#Before
public void setup() {
when(usedAsNonFinal.someMethod(Matchers.any()))
.thenReturn(someObject);
when(usedAsFinal.someMethod(Matchers.any()))
.thenReturn(someObject);
doReturn(someObject).when(service).someMethod(Matchers.any());
}
}
Service, which is under test:
#Service
public class Service {
private SomeObject usedAsNonFinal //injects correctly
private final SomeObject usedAsFinal; //null - not injected
#Autowired
public Service (SomeObject usedAsNonFinal, SomeObject usedAsFinal){
this.usedAsNonFinal = usedAsNonFinal;
this.usedAsFinal = usedAsFinal;
}
//some methods to mock depending on test
}
The problem is - as commented in code - that final field is not getting injected and it's null. When I remove final keyword it gets injected correctly and all tests are working as expected. I tried some tricks from other topics - also using reflection, but nothing seems to be workking in this particular case.
Did you try don't instantiate ServiceTest in test?
#InjectMocks should do it for you. Try just
#Spy
#InjectMocks
private ServiceTest service;

Categories

Resources