JUnit - java.lang.NullPointerException: Cannot invoke "..." because "this.modelMapper" is null - spring-boot

I've been learning Java for about 4 months, so please excuse basic mistakes.
I'm trying to unit test a method from my Service layer:
#Override
#Transactional
public List<StudentDto> getStudentList() {
List<Student> tempList = studentDAO.getStudentList();
List<StudentDto> tempListStudentDto = new ArrayList<>();
for (Student theStudent: tempList) {
tempListStudentDto.add(convertToDto(theStudent));
}
return tempListStudentDto;
}
With this #Test:
// JUnit test for getStudentList()
#Test
#DisplayName("getStudentList()")
public void givenStudentList_whenGettingList_thenReturnList() {
// given -precondition
BDDMockito.given(studentDao.getStudentList())
.willReturn(List.of(newStudentOne, newStudentTwo));
// when - behaviour that we are going to test
List<StudentDto> studentList = studentService.getStudentList();
// then - verify the output
assertAll(
() -> org.assertj.core.api.Assertions.assertThat(studentList).isNotNull(),
() -> org.assertj.core.api.Assertions.assertThat(studentList).size().isEqualTo(2)
);
And I'm constantly getting this error:
java.lang.NullPointerException: Cannot invoke "org.modelmapper.ModelMapper.getConfiguration()" because "this.modelMapper" is null
Could you please help me here or tell me how to convert the Student class to DTO in a testable way?
I've googled the issue and tried all of the suggestions, but could not make it to work.

Related

UNIT TEST: queryForObject method not fully covered the lines

I am trying to mock queryForObject method using Mockito. Unit test actually is passed but the lines is not fully covered.
The code to get the people object is like below:
jdbcTemplate.queryForObject(GET_PEOPLE,
(rs, rowNum) -> new People()
.setId(rs.getInt("id"))
.setFirstName(rs.getString("first_name"))
.setLastName(rs.getString("last_name")),
department, position);
FYI: GET_PEOPLE is a static constant contain the SQL query.
and the unit test is:
People people = new People();
people.setId(1);
people.setFirstName("John");
people.setLastName("Doe");
when(jdbcTemplate.queryForObject(any(), (RowMapper<Object>) any(), any())).thenReturn(people);
Can anyone let me know how to mock to get the lines fully covered. Thanks in advance.
You are not getting coverage because you never execute that code.
You need to call your rowmapper:
#ExtendWith(MockitoExtension.class)
public class MyTest {
#Mock
JdbcTemplate jdbcTemplate;
#Mock
ResultSet resultSet;
#Test
public void myTest() throws SQLException {
when(resultSet.getInt(1)).thenReturn(1);
...
when(jdbcTemplate.queryForObject(any(), (RowMapper<People>) any(), any())).thenAnswer(new Answer<People>() {
#Override
public People answer(InvocationOnMock invocationOnMock) throws Throwable {
RowMapper<People> rowMapper = invocationOnMock.getArgument(1);
return rowMapper.mapRow(resultSet, 1);
}
});
...
}
}

How to test findById method?

First - I've checked all previous topics around this question and none of them helped.
Having the following code:
#DisplayName("GET RecipeUltraLight by id is successful")
#Test
public void givenRecipeId_whenGetRecipeDetailsById_thenReturnRecipeObject(){
// given
given(this.recipeRepository.findById(recipe.getId())).willReturn(Optional.of(recipe));
given(this.recipeService.getRecipeById(recipe.getId())).willReturn(recipe);
given(this.recipeConverter.toUltraLight(recipe)).willReturn(recipeUltraLightDto);
// when
RecipeUltraLightDto retrievedRecipe = recipeService.getRecipeUltraLightById(recipe.getId());
// then
verify(recipeRepository, times(1)).findById(recipe.getId());
verify(recipeService, times(1)).getRecipeById(recipe.getId());
verify(recipeConverter, times(1)).toUltraLight(recipe);
assertThat(retrievedRecipe).isNotNull();
}
gives me this error:
org.mockito.exceptions.misusing.WrongTypeOfReturnValue:
Recipe cannot be returned by findById()
findById() should return Optional
***
If you're unsure why you're getting above error read on.
Due to the nature of the syntax above problem might occur because:
1. This exception *might* occur in wrongly written multi-threaded tests.
Please refer to Mockito FAQ on limitations of concurrency testing.
2. A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies -
- with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.
Service method:
#Transactional(readOnly = true)
public RecipeUltraLightDto getRecipeUltraLightById(Long id) {
Recipe recipe = getRecipeById(id);
RecipeUltraLightDto dto = new RecipeUltraLightDto();
dto = recipeConverter.toUltraLight(recipe);
return dto;
}
// internal use only
#Transactional(readOnly = true)
public Recipe getRecipeById(Long id) {
if (id == null || id < 1) {
return null;
}
return recipeRepository.findById(id)
.orElseThrow(() -> new RecipeNotFoundException(
String.format("Recipe with id %d not found.", id)
));
}
Setup:
#ContextConfiguration(classes = {RecipeService.class})
#ExtendWith({SpringExtension.class, MockitoExtension.class})
class RecipeServiceTest {
#MockBean
private RecipeConverter recipeConverter;
#MockBean
private RecipeRepository recipeRepository;
#Autowired
private RecipeService recipeService;
private Recipe recipe;
private RecipeUltraLightDto recipeUltraLightDto;
#BeforeEach
public void setup(){
recipe = Recipe.builder()
.id(1L)
.name("Recipe")
.description("Description")
.createdAt(LocalDateTime.now())
.difficulty(RecipeDifficulty.EASY)
.minutesRequired(60)
.portions(4)
.authorId(1L)
.views(0)
.isVerified(false)
.build();
recipeUltraLightDto = RecipeUltraLightDto.builder()
.id(1L)
.name("Recipe")
.build();
}
I've tried:
Optinal.ofNullable()
Adding .isPresent()
Getting rid of .orElseThrow and going through if statements and using .get()
Kotlin
Will be glad if someone can help.
You are creating a mock of the object you are testing and with that basically also render the mocking of the repository useless.
You should remove the line given(this.recipeService.getRecipeById(recipe.getId())).willReturn(recipe); that way it will just call the method and call the repository. Which now will return the mocked result. As that is the behavior that will now kick in.
It is clearly mentioned that the method findById() returning Optional, you need to get Recipe by invoking Optional.get().

Unit testing GatewayFilter causes NullPointerException

I'm trying to unit test my GatewayFilter, however I'm having troubles running even simple test.
This is small example of what is failing right now
#ExtendWith(MockitoExtension.class)
public class SomeFilterTest {
private final GatewayFilter gatewayFilter = (exchange, chain) ->
Mono.just("Hello")
.flatMap(this::doSomething)
.switchIfEmpty(Mono.defer(() -> chain.filter(exchange)));
private Mono<Void> doSomething(String value) {
System.out.println(value);
return Mono.empty();
}
#Test
void test1() {
var exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/").build());
var chain = mock(GatewayFilterChain.class);
gatewayFilter.filter(exchange, chain).block();
}
}
Unfortunatelly, it is failing because of
The Mono returned by the supplier is null
java.lang.NullPointerException: The Mono returned by the supplier is
null at java.base/java.util.Objects.requireNonNull(Objects.java:246)
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:44) at
reactor.core.publisher.Mono.subscribe(Mono.java:4361)
And to be honest, I have no idea why is that happening?
You have not stubbed out the filter method call on your mock object, GatewayFilterChain. As a result, the supplier () -> chain.filter(exchange) returns null. You are not allowed to create a Mono with a value of null, hence the exception.
As a result your test should look something like
#Test
public void test1() {
var exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/").build());
var chain = mock(WebFilterChain.class);
// stubbing behaviour on our mock object
given(chain.filter(exchange)).willReturn(Mono.empty());
gatewayFilter.filter(exchange, chain).block();
}
Additionally, I would suggest using StepVerifier instead of using block() in unit tests. This is provided by reactor-test and is purpose built for unit testing reactive code
#Test
public void test1() {
var exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/").build());
var chain = mock(WebFilterChain.class);
given(chain.filter(exchange)).willReturn(Mono.empty());
StepVerifier.create(gatewayFilter.filter(exchange, chain))
.verifyComplete();
}
Here is a very useful Step Verifier Tutorial to help you get started

How do you assert with add object to another object many to many

I'm unit testing a Spring boot web app with Mockito. One of my methods is returning a Actorrest, but if I try to test it, I get compilation errors.
This is the test I wrote:
#Test
void AddActorToChapters() throws NetflixException{
when(actorRepository.findById(MockData.getActor().getId())).thenReturn(Optional.of(MockData.getActor()));
when(chapterService.findChapterById(MockData.getChapter().getId())).thenReturn((MockData.getChapter()));
service.AddActorToChapter(MockData.getChapter().getId(), MockData.getActor().getId());
assertEquals(MockData.getActor().getChapters(), MockData.getChapter());
}
And this is the method I'm trying to test:
#Override
public ActorParticipant AddActorToChapter(Long idActor, Long idChapter) throws NetflixException {
Actor actor = actorRepository.findById(idActor)
.orElseThrow(() -> new NotFoundException("Actor id not found - " + idActor));
if (actorRepository.existsByIdAndChapters_Id(idActor, idChapter)) {
throw new DuplicateException("Actor id found - " + idActor);
}
Chapter chapter = chapterService.findChapterById(idChapter);
actor.getChapters().add(chapter);
actorRepository.save(actor);
ActorParticpateMapper mapper = new ActorParticpateMapper();
return mapper.mapActorToActorParticipant(actor);
}
and the database mockdata are
public class MockData {
public static Actor getActor() {
Actor actor = new Actor();
actor.setId(1L);
actor.setName("ali");
actor.setNationality("ameriacn");
actor.getChapters().add(getChapter());
return actor;
}
public static Chapter getChapter() {
Chapter chapter = new Chapter();
chapter.setId(1L);
chapter.setName("Chapter 7");
return chapter;
}}
log error
java.lang.Exception: No tests found matching [{ExactMatcher:fDisplayName=AddActorToChapters], {ExactMatcher:fDisplayName=AddActorToChapters(actortest.ActorServiceTesting)], {LeadingIdentifierMatcher:fClassName=actortest.ActorServiceTesting,fLeadingIdentifier=AddActorToChapters]] from org.junit.internal.requests.ClassRequest#64b8f8f4
at org.junit.internal.requests.FilterRequest.getRunner(FilterRequest.java:40)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.createFilteredTest(JUnit4TestLoader.java:83)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.createTest(JUnit4TestLoader.java:74)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestLoader.loadTests(JUnit4TestLoader.java:49)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:513)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:756)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:452)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
With the JUnit 4 test runner you are using, the test methods must be defined as public.

Errors: UnfinishedStubbing

I am writing Junit test case and I want to mock KafkaTemplate method kafkaTemplate.send(TOPIC_NAME, "someData");. In my project, I am using spring boot and Kafka.
Below is the StudentRecords class. I am using mockito for mocking the dependencies.
#Component
public class StudentRecords {
#Autowired
private KafkaTemplate<String, String> kafkaTemplate;
#Value("${topicNameForStudents}")
private String TOPIC_NAME;
public String sendStudentData(StudentDTO studentDTO) {
String studentStr = null;
try {
if(null == studentDTO) {
throw new StudentException("studentDTO Object cant be null");
}
if(studentDTO.getId() == null) {
throw new StudentException("Id cant be empty");
}
ObjectMapper mapper = new ObjectMapper();
studentStr = mapper.writeValueAsString(srvgExecution);
kafkaTemplate.send(TOPIC_NAME, studentStr);
return "SUCCESS";
} catch (JsonProcessingException e) {
e.printStackTrace();
return "ERROR";
}
}
}
And test class is as follows:
#ExtendWith({ SpringExtension.class, MockitoExtension.class })
class StudentRecordsTest {
#InjectMocks
StudentRecords studentRec;
#Mock
private KafkaTemplate<String, String> kafkaTemplate;
#Test
void testSendStudentData() {
StudentDTO studentDTO = new StudentDTO();
studentDTO.setId(1);
studentDTO.setName("ABC");
studentDTO.setAddress("Some Address");
Mockito.when(kafkaTemplate.send(Mockito.anyString(), Mockito.anyString()));
studentRec.sendStudentData(studentDTO);
}
}
And I getting the following error
[ERROR] Errors:
[ERROR] studentRec.testSendStudentData: ยป UnfinishedStubbing
It is happening at line studentRec.sendStudentData(studentDTO);
How I can resolve/write the junit for this?
#Test
void testSendStudentData() {
StudentDTO studentDTO = new StudentDTO();
studentDTO.setId(1);
studentDTO.setName("ABC");
studentDTO.setAddress("Some Address");
Mockito.when(kafkaTemplate.send(Mockito.anyString(), Mockito.anyString()));
studentRec.sendStudentData(studentDTO);
Mockito.verify(kafkaTemplate).send(Mockito.anyString(), Mockito.anyString());
}
after updating the junit to above one, ended up with below error at this statement Mockito.verify(kafkaTemplate).send(Mockito.anyString(), Mockito.anyString());
Argument(s) are different! Wanted:
kafkaTemplate.send(
<any string>,
<any string>
);
Your mock statement is incomplete.
Mockito.when(kafkaTemplate.send(Mockito.anyString(), Mockito.anyString()));
KafkaTemplate's send method returns a ListenableFuture object and hence you need to have your mock return it.
I understand, you are not really using the returned value as part of your code.
In that case you may simply return null as below.
Mockito.when(kafkaTemplate.send(Mockito.anyString(), Mockito.anyString())).thenReturn(null);
Although, I would suggest you should ideally check for return value for better error handling, but that can be a different story altogether.
In case you do plan to handle error by checking the return value, your above mock statement can be written to return both success and fail cases.
You may check below thread for more details on how to set the correct mock expectations for KafkaTemplate.
How to mock result from KafkaTemplate

Resources