I am practising restful api endpoints using https://api.predic8.de/shop/docs
Here is my repo
I am getting a NPE failure when I try to use #InjectMocks during my TDD approach
However, I can make my test pass when I make a direct call in the setup()
vendorService = new VendorServiceImpl(VendorMapper.INSTANCE, vendorRepository);
I wanted to extend my learning by trying to create an endpoint for getting all vendors.
When I employ TDD along the way, but, my test getAllVendors() fails on a NPE when I try to use #InjectMocks but passes when I substitute it for a direct call in the setup() method.
The NPE is linked to the mapper class I think.
Here are the classes that I believe are useful. VendorServiceTest, VendorServiceImpl, VendorMapper.
I have commented out the direct call in the setup as I want to get the test passing using #InjectMocks
package guru.springfamework.services;
import guru.springfamework.api.v1.mapper.VendorMapper; import
guru.springfamework.api.v1.model.VendorDTO; import
guru.springfamework.domain.Vendor; import
guru.springfamework.repositories.VendorRepository; import
org.junit.Before; import org.junit.Test; import
org.mockito.InjectMocks; import org.mockito.Mock; import
org.mockito.MockitoAnnotations; import
org.springframework.test.web.servlet.MockMvc;
import java.util.Arrays; import java.util.List;
import static org.junit.Assert.*; import static
org.mockito.Mockito.when;
public class VendorServiceTest {
public static final String NAME = "Tasty";
public static final Long ID = 1L;
#Mock
VendorMapper vendorMapper;
#Mock
VendorRepository vendorRepository;
#InjectMocks
VendorServiceImpl vendorService;
//VendorService vendorService;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
//vendorService = new VendorServiceImpl(VendorMapper.INSTANCE, vendorRepository);
}
#Test
public void getAllVendors() {
//given
List<Vendor> vendors = Arrays.asList(new Vendor(), new Vendor(), new Vendor());
when(vendorRepository.findAll()).thenReturn(vendors);
//when
List<VendorDTO> vendorDTOList = vendorService.getAllVendors();
//then
assertEquals(3, vendorDTOList.size());
}
#Test
public void findByName() {
}
}
package guru.springfamework.services;
import guru.springfamework.api.v1.mapper.VendorMapper; import
guru.springfamework.api.v1.model.VendorDTO; import
guru.springfamework.repositories.VendorRepository; import
org.springframework.stereotype.Service;
import java.util.List; import java.util.stream.Collectors;
#Service public class VendorServiceImpl implements VendorService {
private final VendorMapper vendorMapper;
private final VendorRepository vendorRepository;
public VendorServiceImpl(VendorMapper vendorMapper, VendorRepository vendorRepository) {
this.vendorMapper = vendorMapper;
this.vendorRepository = vendorRepository;
}
#Override
public List<VendorDTO> getAllVendors() {
return vendorRepository
.findAll()
.stream()
.map(vendor -> {
VendorDTO vendorDTO = vendorMapper.vendorToVendorDTO(vendor);
vendorDTO.setVendorUrl("/api/v1/vendors/" + vendor.getId());
return vendorDTO;
})
.collect(Collectors.toList());
}
#Override
public VendorDTO findByName(String name) {
return vendorMapper.vendorToVendorDTO(vendorRepository.findByName(name));
}
#Override
public VendorDTO getVendorById(Long id) {
return vendorMapper.vendorToVendorDTO(vendorRepository.findById(id).orElseThrow(RuntimeException::new));
}
}
package guru.springfamework.api.v1.mapper;
import guru.springfamework.api.v1.model.VendorDTO; import
guru.springfamework.domain.Vendor; import org.mapstruct.Mapper; import
org.mapstruct.factory.Mappers;
#Mapper public interface VendorMapper {
VendorMapper INSTANCE = Mappers.getMapper(VendorMapper.class);
VendorDTO vendorToVendorDTO(Vendor vendor);
}
Does anyone know where and why I am going wrong?
The problem is that you created mock object for the mapper, but you didn't say what should happen when the method vendorToVendorDTO is called.
Therefore, when that method is called in the next line of code:
VendorDTO vendorDTO = vendorMapper.vendorToVendorDTO(vendor);
It will return null, and then in this line of code:
vendorDTO.setVendorUrl("/api/v1/vendors/" + vendor.getId());
You will get NullPointerException.
To make this work, change your getAllVendors() method as follows:
#Test
public void getAllVendors() {
//given
List<Vendor> vendors = Arrays.asList(new Vendor(), new Vendor(), new Vendor());
VendorDTO mockDto = mock(VendorDTO.class);
when(vendorRepository.findAll()).thenReturn(vendors);
when(vendorMapper.vendorToVendorDTO(any(Vendor.class))).thenReturn(mockDto);
//when
List<VendorDTO> vendorDTOList = vendorService.getAllVendors();
//then
assertEquals(3, vendorDTOList.size());
}
And the test should pass.
Have you tried to put #RunWith(MockitoJUnitRunner.class)/#ExtendsWith(MockitoExtension.class) over your test class?
Related
For example I have the following classes below:
public class TesteEstatico {
public static String teste(){
return "FOO";
}
}
And I have a class that uses her method:
public class UsaTesteEstatico {
public String metodoParaTeste1 (){
return TesteEstatico.teste() + " BAR ";
}
public String metodoParaTeste2 (){
return "FOO "+TesteEstatico.teste() + " BAR ";
}
}
Test class:
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
#ExtendWith(MockitoExtension.class) public class UsaTesteEstaticoTest {
#InjectMocks
UsaTesteEstatico usaTesteEstatico;
#Test
void teste1(){
Mockito.mockStatic(TesteEstatico.class);
Mockito.when(TesteEstatico.teste())
.thenReturn("BANANA");
String res = usaTesteEstatico.metodoParaTeste1();
System.out.println(res);
}
#Test
void teste2(){
Mockito.mockStatic(TesteEstatico.class);
Mockito.when(TesteEstatico.teste())
.thenReturn("LARANJA");
String res = usaTesteEstatico.metodoParaTeste2();
System.out.println(res);
}
}
Error I get when trying to run the tests:
org.mockito.exceptions.base.MockitoException:
For TesteEstatico, static mocking is already registered in the current thread
To create a new mock, the existing static mock registration must be deregistered
Versions of the libs that are in the project:
junit-jupiter 5.5.2
mockito-junit-jupiter 3.2.14
mockito-inline 3.2.14
Any idea how to solve this, i've tried a few things but nothing successful.
NOTE: I cannot change or add any new libraries as it is a restricted project.
You should use try-with-resources block in each of the tests to close the mockStatic.
public class UsaTesteEstaticoTest {
UsaTesteEstatico usaTesteEstatico = new UsaTesteEstatico();
#Test
void teste1(){
try (var ms = Mockito.mockStatic(TesteEstatico.class)) {
Mockito.when(TesteEstatico.teste()).thenReturn("BANANA");
String res = usaTesteEstatico.metodoParaTeste1();
System.out.println(res);
}
}
#Test
void teste2(){
try (var ms = Mockito.mockStatic(TesteEstatico.class)) {
Mockito.when(TesteEstatico.teste()).thenReturn("LARANJA");
String res = usaTesteEstatico.metodoParaTeste2();
System.out.println(res);
}
}
}
Note on mockStatic in #BeforeAll
Using #BeforeAll is a trap and bad advice.
You should strive for independent tests that don't affect each other.
This is not the case for mockStatic called in #BeforeAll, as stubbing from test methods outlive the test methods.
For example
// BAD CODE DONT USE
public class UsaTesteEstaticoTest {
UsaTesteEstatico usaTesteEstatico = new UsaTesteEstatico();
static MockedStatic<TesteEstatico> ms;
#BeforeAll
public static void init() {
ms = Mockito.mockStatic(TesteEstatico.class);
}
#AfterAll
public static void close() {
ms.close();
}
#Test
void teste1() {
Mockito.when(TesteEstatico.teste()).thenReturn("BANANA");
String res = usaTesteEstatico.metodoParaTeste1();
System.out.println(res);
}
#Test
void teste2() {
String res = usaTesteEstatico.metodoParaTeste2();
System.out.println(res);
}
}
teste2 prints:
FOO BANANA BAR if run after teste1
FOO null BAR if run separately
This is precisely what you want to avoid.
you need to use static block to mock it.
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
#ExtendWith(MockitoExtension.class)
public class UsaTesteEstaticoTest {
#InjectMocks
UsaTesteEstatico usaTesteEstatico;
#BeforeAll
public static void init(){
Mockito.mockStatic(TesteEstatico.class);
}
#Test
void teste1(){
Mockito.when(TesteEstatico.teste())
.thenReturn("BANANA");
String res = usaTesteEstatico.metodoParaTeste1();
System.out.println(res);
}
#Test
void teste2(){
Mockito.when(TesteEstatico.teste())
.thenReturn("LARANJA");
String res = usaTesteEstatico.metodoParaTeste2();
System.out.println(res);
}
}
I have an actor class EmployeeActor, inside that actor, some other actor is fired using payrollRunActor.tell(). I need to write a JUnit test for EmployeeActor.java, but I don't want to fire payrollRunActor.tell(), means I want to mock it.
Is there a way to do it? I tried a lot, but real payrollRunActor is getting fired.
Here is the actual code of my EmployeeActor class.
package com.test.periodic.actors;
import java.util.List;
import org.apache.commons.lang3.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.test.avs.domain.boundedcontext.Employee;
import com.test.avs.domain.boundedcontext.PayrollRun;
import com.test.entity.BusinessDTO;
import com.test.periodic.actors.aggregrators.EmployeeAggregator;
import akka.actor.AbstractActor;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import akka.routing.RoundRobinPool;
public class EmployeeActor extends AbstractActor {
private static final Logger logger = LoggerFactory.getLogger(EmployeeActor.class);
private boolean rollup;
public static Props props() {
return Props.create(EmployeeActorTest.class);
}
private List<PayrollRun> payrollRuns;
private String instanceId;
private String employeeAggregatorId;
private Employee employee;
private ActorRef organizationAggregatorActor;
private List<BusinessDTO> businessDTOs;
final ActorSystem payrollRunSystem = ActorSystem.create("payrollRun");
ActorRef employeeAggregator;
public EmployeeActor(ActorRef organizationAggregatorActor, List<PayrollRun> payrollRuns,
Employee employee, List<BusinessDTO> businessDTOs, boolean rollup) {
this.payrollRuns = payrollRuns;
this.employee = employee;
this.organizationAggregatorActor = organizationAggregatorActor;
this.businessDTOs = businessDTOs;
this.rollup = rollup;
}
#Override
public void preStart() throws Exception {
instanceId = RandomStringUtils.randomAlphanumeric(6);
employeeAggregatorId = "employeeAggregator-" + instanceId;
employeeAggregator = getContext().system().actorOf(
Props.create(EmployeeAggregator.class, organizationAggregatorActor, employee),
employeeAggregatorId);
super.preStart();
}
#Override
public Receive createReceive() {
return receiveBuilder().match(Employee.class, employee -> {
if (rollup) {
logger.info("Rollingup business entities.");
employeeAggregator.tell(employee, getSelf());
} else {
ActorRef payrollRunActor = payrollRunSystem.actorOf(new RoundRobinPool(payrollRuns.size())
.props(Props.create(PayrollRunActor.class, employeeAggregator, employee, businessDTOs)));
for (PayrollRun payrollRun : payrollRuns) {
**payrollRunActor.tell(payrollRun, getSelf());**
}
}
}).match(PayrollRun.class, maxPaydatePayrollRun -> {
ActorRef payrollRunActor = payrollRunSystem
.actorOf(Props.create(PayrollRunActor.class, employeeAggregator, employee, businessDTOs));
**payrollRunActor.tell(maxPaydatePayrollRun, getSelf());**
}).build();
}
}
First of all you would have to mock the static method call which is invoked during the creation of class under test. Then make it return a spied object and mock the method you want to avoid calling:
#RunWith(PowerMockRunner.class)
#PrepareForTest(ActorSystem.class)
public void TestClass{
#Test
public void test(){
// Arrange
PowerMockito.mockStatic(ActorSystem.class);
ActorSystem actorSystemMock = Mockito.mock(ActorSystem.class);
Actor actorSpy = Mockito.spy(new Actor());
Mockito.when(ActorSystem.create("payrollRun")).thenReturn(actorSystemSpy);
Mockito.when(actorSystemMock.actorOf(any(RoundRobinPool.class)))
.thenReturn(actorSpy);
Mockito.doNothing().when(actorSpy)
.tell(Mockito.any(PayrollRun.class), Mockito.any(Self.class));
EmployeeActor employeeActor = new EmployeeActor();
// Act and assert...
employeeActor.createReceive();
}
}
Remember that all other methods of actorSystemSpy will be called will real implementation. If you want to mock all of them then use Mockito.mock instead of spy.
I have a simple line of Code:
DraftCampaignDetails createdDraft = draftCampaignI.createDraftCampaign(ConvertionUtil
.getDraftCampaignDetailsfromCreateDraftRequest(request));
I am trying to mock it like this:
ConvertionUtil action1 = PowerMockito.mock(ConvertionUtil.class);
when(action1.getDraftCampaignDetailsfromCreateDraftRequest(request)).thenReturn(details);
when(draftCampaignI.createDraftCampaign(details)).thenReturn(details);
But I am getting this error:
when() requires an argument which has to be 'a method call on a mock'.
Adding entire test class for more clarity:
public class DraftCampaignActivityTest {
#Mock
IDraftCampaign draftCampaignI;
/* #Mock
ConvertionUtil util;*/
#Before
#SuppressWarnings("unchecked")
public void setup()
{
MockitoAnnotations.initMocks(this);
}
#Test
public void createDraft_newDraft() {
DraftCampaignActivity draftContoller = new DraftCampaignActivity();
CreateDraftCampaignRequest request = createRequest();
DraftCampaignDetails details = buildDraftDetails();
if(draftCampaignI != null){
System.out.println("sccdscscd");
}
/*
if(util != null) {
System.out.println("wewewew");
}*/
/// ConvertionUtil action1 = PowerMockito.mock(ConvertionUtil.class);
PowerMockito.mockStatic(ConvertionUtil.class);
PowerMockito.when(
ConvertionUtil.getDraftCampaignDetailsfromCreateDraftRequest(request)
).thenReturn(details);
when(draftCampaignI.createDraftCampaign(details)).thenReturn(details);
// when(util.getDraftCampaignDetailsfromCreateDraftRequest(request)).thenReturn(details);
CreateDraftCampaignResponse response = new CreateDraftCampaignResponse();
draftContoller.createDraftCampaign(request);
response.setDraftCampaignId(details.getDraftId());
Assert.assertEquals(response.getDraftCampaignId(),"ww");
}
private DraftCampaignDetails buildDraftDetails() {
DraftCampaignDetails details = new DraftCampaignDetails();
details.setDraftId("ww");
return details;
}
private CreateDraftCampaignRequest createRequest() {
CreateDraftCampaignRequest request = new CreateDraftCampaignRequest();
request.setCampaignInfo("campaignInfo");
request.setMarketplaceId("adadedaedaed");
DraftCampaignDetailsBase base = new DraftCampaignDetailsBase();
Money money = new Money();
money.setCurrencyCode("USD");
money.setMillicents(10L);
base.setCampaignBudget(money);
base.setCampaignName("name");
base.setDraftCampaignState("DRAFT");
request.setDraftCampaignDetailsBase(base);
return request;
//request
}
I am new to Mockito and Powermock. please help! Any help will be greatly appreciated!
To work draftCampaignI must be injected into draftContoller, to do so you need to declare draftContoller as a field of your test class annotated with #InjectMocks, no need to create the instance of DraftCampaignActivity explicitly anymore, leave it to Mockito, as next:
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import static org.mockito.Mockito.when;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
public class DraftCampaignActivityTest {
#Mock
IDraftCampaign draftCampaignI;
#InjectMocks
DraftCampaignActivity draftContoller;
#Test
#PrepareForTest(ConvertionUtil.class)
public void createDraft_newDraft() {
CreateDraftCampaignRequest request = new CreateDraftCampaignRequest();
DraftCampaignDetails details = new DraftCampaignDetails();
PowerMockito.mockStatic(ConvertionUtil.class);
PowerMockito.when(
ConvertionUtil.getDraftCampaignDetailsfromCreateDraftRequest(request)
).thenReturn(details);
when(draftCampaignI.createDraftCampaign(details)).thenReturn(details);
draftContoller.createDraftCampaign(request);
}
}
Assuming that the class DraftCampaignActivity is of type:
public class DraftCampaignActivity {
...
private IDraftCampaign draftCampaignI;
...
}
More details about the annotation InjectMocks.
NB: As we use #RunWith(PowerMockRunner.class), we have no need to call MockitoAnnotations.initMocks(this) explicitly as it will be done internally such that the method setup is useless and can be removed.
I have mocked a method called methodA().
I have a linked list called linkedListA.
Now,
i have a line of code to mock the return of methodA, as such
when(methodA()).thenReturn(linkedListA.get(0)).thenReturn(linkedListA.get(1)).thenReturn(linkedListA.get(2)) and so on
Now, is there a more efficient/cleaner way to write all the thenReturns, for instance, like in a loop? So, that I do not have to write tons of thenReturns
Thanks
I think the first improvement would be to use this:
when(methodA()).thenReturn(linkedListA.get(0), linkedListA.get(1), linkedListA.get(2)) and so on
Moreover, you could you the thenAnswer method to return a value:
final AtomicInteger i = new AtomicInteger(0);
when(methodA()).thenAnswer(new Answer<YourType>() {
#Override
public YourType answer(InvocationOnMock invocation) {
return linkedListA.get(i.getAndIncrement());
}
});
Example:
import static org.powermock.api.mockito.PowerMockito.when;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
#RunWith(PowerMockRunner.class)
#PrepareForTest(Blub.class)
public class Mockexample {
#Test
public void test() {
Blub blub = PowerMockito.mock(Blub.class);
final List<Integer> counter = Arrays.asList(1, 2, 3);
final AtomicInteger i = new AtomicInteger(0);
// blub.size() is final, only reason to use PowerMockito here
when(blub.size()).thenAnswer(new Answer<Integer>() {
#Override
public Integer answer(InvocationOnMock invocation) throws Throwable {
return counter.get(i.getAndIncrement());
}
});
System.out.println(blub.size());
System.out.println(blub.size());
System.out.println(blub.size());
}
}
The Blub clas:
public class Blub {
public final int size() {
return 0;
}
}
Is it possible to have a Junit rule only apply to specific tests? If so, how do I do that?
The code below exemplifies what I want to do: each time I have #Rule, I want the method below that to have the specific rule that has been annotated to run with it. I only want that rule to run with the corresponding test. I don't want anything other tests to be affected by the rule.
In this case, when I run these tests, I see that one of the tests the EmptyFileCheck, gives a File DNE does not exist, but I have used a separate annotation for that function, so I had thought that it would run with a different context, supplying the Empty, but instead DNE is till being used.
import static java.lang.System.in;
import static java.lang.System.setIn;
import static org.junit.Assert.fail;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.PrintStream;
import java.nio.channels.Pipe;
import static org.hamcrest.core.AllOf.allOf;
import org.hamcrest.Matcher;
import org.hamcrest.core.AllOf;
import static org.hamcrest.Matchers.*;
import org.hamcrest.text.StringContains;
import org.hamcrest.text.StringEndsWith;
import org.hamcrest.text.StringStartsWith;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.jmock.lib.legacy.ClassImposteriser;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.contrib.java.lang.system.TextFromStandardInputStream;
import org.junit.runner.RunWith;
public class UnitTests {
private Mockery context = new Mockery() {{
setImposteriser(ClassImposteriser.INSTANCE);
}};
private main mn;
private InputStream oldIn;
private PrintStream oldOut;
private InputStream mockIn;
private InputStreamReader mockinputStream;
private PrintStream mockOut;
private BufferedReader reader;
private Expectations exp;
#Before
public void setMinimalMockingExpectations() throws IOException {
exp = new Expectations() {{ }};
mn = context.mock(main.class);
mockinputStream = context.mock(InputStreamReader.class);
oldIn = System.in;
oldOut = System.out;
mockIn = context.mock(InputStream.class);
mockOut = context.mock(PrintStream.class);
System.setOut(mockOut);
}
public void configureExpectations(boolean fileOrInput, boolean verbosity) {
exp.one(mockOut).println("Do you want to process standard (I)nput, or a (F)ile? I/F");
if (fileOrInput) { //it's a file
exp.one(mockOut).println("Enter filename: ");
} else { //it's not
}
}
#After
public void reset() {
System.setOut(oldOut);
}
#Rule
public final TextFromStandardInputStream FileNotFoundException
= new TextFromStandardInputStream("F\nDNE\n");
#Test(expected=FileNotFoundException.class)
public void EnsureFileCheckExists() throws IOException {
final String fileName = "DNE";
configureExpectations(true, false);
exp.one(mn).checkFile(fileName);
context.checking(exp);
mn.main(null);
}
#Rule
public final TextFromStandardInputStream FileReadAccessDenied
= new TextFromStandardInputStream("F\nUnderPriviledged\n");:w
#Test(expected=FileNotFoundException.class)
public void FileReadAccessDenied() throws java.io.FileNotFoundException {
final String fileName = "UnderPriviledged";
configureExpectations(true, false);
//exp.oneOf(mn).checkFile(with()); TODO: fix ME!
context.checking(exp);
mn.main(null);
}
#Rule
public final TextFromStandardInputStream EmptyFileCheck
= new TextFromStandardInputStream("F\nEmpty\n");
#Test
public void EmptyFileCheck() throws java.io.FileNotFoundException {
final String fileName = "Empty";
configureExpectations(true, false);
exp.one(mn).checkFile(fileName);
context.checking(exp);
mn.main(null);
}
}
You could have a setter in your Rule which is the first thing that gets called in the rule. Something like this, from ExpectedException:
// These tests all pass.
public static class HasExpectedException {
#Rule
public ExpectedException thrown= ExpectedException.none();
#Test
public void throwsNothing() {
// no exception expected, none thrown: passes.
}
#Test
public void throwsNullPointerException() {
thrown.expect(NullPointerException.class);
throw new NullPointerException();
}
#Test
public void throwsNullPointerExceptionWithMessage() {
thrown.expect(NullPointerException.class);
thrown.expectMessage("happened?");
thrown.expectMessage(startsWith("What"));
throw new NullPointerException("What happened?");
}
}
Any reason not to just take the code out of the #rule annotation and move it to the start of the test body?