Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Junit 5 + Mockito in Service Layer FetchById Method return null object retrieve from service

I tried to test the FetchById method in my BookServiceTest using Mockito but this error occurred
I’m using JUnit 5 and Mockito, that come along with spring boot starter test in spring boot version 3.1.3

the error:

org.opentest4j.AssertionFailedError: expected: not <null>

    at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:152)
    at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
    at org.junit.jupiter.api.AssertNotNull.failNull(AssertNotNull.java:49)
    at org.junit.jupiter.api.AssertNotNull.assertNotNull(AssertNotNull.java:35)
    at org.junit.jupiter.api.AssertNotNull.assertNotNull(AssertNotNull.java:30)
    at org.junit.jupiter.api.Assertions.assertNotNull(Assertions.java:301)
    at com.bookstore.com.serviceLevelTest.BookServTest.isFetchByIdValid(BookServTest.java:123)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
    at java.base/java.lang.reflect.Method.invoke(Method.java:578)
    at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:727)
    at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
    at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147)
    at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86)
    at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103)
    at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
    at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
    at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92)
    at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:217)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:213)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:138)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:68)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:147)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:127)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:90)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:55)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:102)
    at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:54)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
    at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
    at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
    at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:57)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
    at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
    at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232)
    at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55)

Here is my test class:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

@ExtendWith(MockitoExtension.class)
public class BookServTest {

    private static final Logger logger = LoggerFactory.getLogger(BookServTest.class);
    @Mock
    private BookRepository bookRepository;

    @Mock
    private ModelMappers modelMapper;
    @Mock
    AuthorService authorService;


    private BookService bookService;


    //Mock Object

    List<Book> bookDtos;
    private Book book;


    private BookDto bookDto;
    private Author author;

    @BeforeEach
    public void setUp(){
    bookService = new BookService(modelMapper,bookRepository,authorService);

        //Create BookDto
        bookDto = new BookDto();
        bookDto.setId(1L);
        bookDto.setTitle("The Usual Suspect");
        bookDto.setCategory("Crime");
        bookDto.setPrice(7800.55);
        bookDto.setAuthorName("Somxai");

        //Create Book
        book = new Book();
                book.setId(1L);
                book.setTitle("The Usual Suspect");
                book.setCategory("Crime");
                book.setPrice(7800.55);

        //Create list of bookDto
        bookDtos = new ArrayList<>();
        bookDtos.add(new Book(1L, "The Usual Suspect","Crime",7800.50));
        bookDtos.add(new Book(2L, "The Shutter Island","Crime",9000.50));
        bookDtos.add(new Book(3L, "The Shutter Island","Crime",9000.50));

        //Create Author
        author = new Author("Somxai","SSM","Laos PDR");

    }


//The error method:
 @Test
    void isFetchByIdValid(){
        //Arrange
        Mockito.when(bookRepository.fetchById(1L)).thenReturn(Optional.of(book)); //as i have checked this method is ok
        //Act
        BookDto bookDTO = bookService.fetchById(1L); // bookDTO return null
        //Assert
        Assertions.assertNotNull(bookDTO);

    }

//this method work fine
 @Test
    void isFetchAllValid(){
        //Arrange
        Pageable pageable = PageRequest.of(0,3,Sort.by("title").descending());
        Page<Book> expectedPage = new PageImpl<>(bookDtos, pageable, bookDtos.size());
        Mockito.when(bookRepository.findAll(pageable)).thenReturn(expectedPage);
        //Act
        List<BookDto> bookDtos1 = bookService.fetchAll(0,3,"title");
        //Assertion
        Assertions.assertNotNull(bookDtos1);
        Assertions.assertEquals(3,bookDtos1.size());
    }

Here is service method:

@Transactional
    @Cacheable(value = "book", key = "#id")
    public BookDto fetchById(Long id) {
        Optional<Book> book = bookRepository.fetchById(id);
        if (book.isEmpty()) {
            logger.info("book not found");
        }
        Book book1 = book.get();

        return modelMapper.bookToDTO(book1);
    }

Here is repository method:



    @Transactional
    @Query(value = "SELECT b FROM Book b JOIN FETCH b.author a WHERE b.id = :id")
    Optional<Book> fetchById(@Param("id") Long id);

Here is mapping method from model mapper:

public BookDto bookToDTO(Book book){

            BookDto bookDto = new BookDto();
            bookDto = modelMapper().map(book, BookDto.class);
            if (book.getAuthor() != null){
                bookDto.setAuthorName(book.getAuthor().getFirstName() + " " + book.getAuthor().getLastName());
            }
            return bookDto;
        }

I have been searching for a similar issue and tried many approaches but not work for me.
note: When I tested in Postman, every method working fine.
Thanks in advance.

>Solution :

The issue you are encountering where bookDTO is null in your isFetchByIdValid test is likely due to a problem in your mock setup or how the modelMapper is used. Here are some steps to troubleshoot and resolve the issue:

  1. Ensure the bookRepository.fetchById(1L) mock setup is correct:

    In your test, you have this line:

    Mockito.when(bookRepository.fetchById(1L)).thenReturn(Optional.of(book));
    

    Make sure that the bookRepository is properly mocked and that the fetchById method is being called with 1L. Also, ensure that the book object being returned is correctly set up and not null.

  2. Verify the modelMapper:

    Check your modelMapper configuration and ensure that it is correctly mapping a Book entity to a BookDto. The issue might be with how the modelMapper is set up or with the mapping logic itself.

  3. Debugging:

    You can add some debug statements to your test and service method to help diagnose the issue. For example, you can print the values of book, book1, and bookDTO in your test to see where the null value is coming from.

    @Test
    void isFetchByIdValid() {
        // Arrange
        Mockito.when(bookRepository.fetchById(1L)).thenReturn(Optional.of(book));
    
        // Act
        BookDto bookDTO = bookService.fetchById(1L);
    
        // Debugging
        System.out.println("book: " + book);
        System.out.println("book1: " + book1);
        System.out.println("bookDTO: " + bookDTO);
    
        // Assert
        Assertions.assertNotNull(bookDTO);
    }
    

    In your service method, you can add log statements to check if book is being fetched and if the mapping to bookDTO is successful:

    @Transactional
    @Cacheable(value = "book", key = "#id")
    public BookDto fetchById(Long id) {
        Optional<Book> book = bookRepository.fetchById(id);
        if (book.isEmpty()) {
            logger.info("Book not found");
        } else {
            logger.info("Book found: " + book.get()); // Log the book object
        }
    
        Book book1 = book.get();
        logger.info("Mapping book to bookDTO...");
        BookDto bookDTO = modelMapper.bookToDTO(book1);
        logger.info("Mapped book to bookDTO: " + bookDTO); // Log the bookDTO object
    
        return bookDTO;
    }
    

    This should help you pinpoint where the issue is occurring.

  4. Check the modelMapper configuration:

    Ensure that the modelMapper is correctly configured to map a Book entity to a BookDto. Double-check that the mapping logic is correct and that it’s not causing any issues.

By following these steps, you should be able to identify and resolve the issue causing bookDTO to be null in your test. It’s likely related to either the mock setup, the modelMapper configuration, or how the mapping is performed in your service method.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading