0

I developed an application which stores data related to Books in MongoDB and pass the data to the frontend using Spring Rest api. In here I only get the data from the database, hence GetMapping is only used and it works fine.
When I try to test that get method there's an Null pointer error and it happens when trying to findAll() data. Help me to solve this issue and make the test of that method work finely.

API

@RestController
@RequestMapping("/api")
public class Controller {

@Autowired
    BookRepository bookRepo;

@GetMapping("/books")
    public List<Book> getBooks(){
        return bookRepo.findAll();
    }
}

Unit test class

    class BookControllerTest {

    private Controller controller;
    
    @Mock
    private BookRepository repository;

    @Test
    public void getBooksTest(){

        Book b1 = new Book("12345","James","male");
        Book b2 = new Book("67890","Vicky","Female");

        List<Book> bookList = new ArrayList<>();
        bookList.add(b1);
        bookList.add(b2);
        System.out.println(bookList);

        when(repository.findAll()).thenReturn(bookList);
        List<Book> newList = controller.getBooks();
        System.out.println(newList);

        assertEquals(2,newList.size());
    }

}

Error Log

java.lang.NullPointerException
at com.example.demo.BookControllerTest.getBooksTest(BookControllerTest.java:51)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:686)
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:149)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
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.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:212)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:208)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:137)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:71)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at java.util.ArrayList.forEach(ArrayList.java:1249)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at java.util.ArrayList.forEach(ArrayList.java:1249)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:248)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$5(DefaultLauncher.java:211)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:226)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:199)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:132)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:74)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

51 line refers to when(repository.findAll()).thenReturn(bookList);

ArchieVon
  • 183
  • 1
  • 2
  • 16
  • How you are making the Controller controller object. Seems that is null pointer exception root. Add stack trace to your question too. – Amit Vyas Jul 21 '20 at 15:44
  • https://www.baeldung.com/spring-boot-testing#unit-testing-with-webmvctest will help to identify what kind of test you are trying to achieve. As per the label, I believe it is a unit test. – Amit Vyas Jul 21 '20 at 16:13

2 Answers2

0

You need to provide the annotation at class level for this , like below if ure using spring boot test starter @RunWith(SpringRunner.class) or @RunWith(MockitoJUnitRunner.class) and @InjectMocks on the variable which you want to test

@RunWith(SpringRunner.class)
class BookControllerTest {

    @InjectMocks
    private Controller controller;
    
    @Mock
    private BookRepository repository;

    @Test
    public void getBooksTest(){

        Book b1 = new Book("12345","James","male");
        Book b2 = new Book("67890","Vicky","Female");

        List<Book> bookList = new ArrayList<>();
        bookList.add(b1);
        bookList.add(b2);
        System.out.println(bookList);

        when(repository.findAll()).thenReturn(bookList);
        List<Book> newList = controller.getBooks();
        System.out.println(newList);

        assertEquals(2,newList.size());
    }
    
    }
ArchieVon
  • 183
  • 1
  • 2
  • 16
Pandit Biradar
  • 1,777
  • 3
  • 20
  • 35
0

You can get your tests working by using @RunWith(SpringRunner.class) or @RunWith(MockitoJUnitRunner.class) as answered here.

There are a couple for things I would like to suggest.

  • In this case, use @RunWith(MockitoJUnitRunner.class) as there is no use of loading complete ApplicationContext which consumes a lot of time. Using MockitoJUnitRunner is fast and tests should be as fast as possible.
  • Use constructor injection instead of field injection. Give this a read. Your code would look like:
@RestController
@RequestMapping("/api")
public class BooksController {

    private BookRepository bookRepository;

    @Autowired
    public BooksController(BookRepository bookRepository) {
        this.bookRepository = bookRepository;
    }

    @GetMapping("/books")
    public List<Books> getBooks() {
        return bookRepository.findAll();
    }

}
@RunWith(MockitoJUnitRunner.class)
public class BooksControllerTest {

    @Mock
    private BookRepository bookRepository;

    private BooksController booksController;

    @Before
    public void setUp() {
        booksController = new BooksController(bookRepository);
    }

    @Test
    public void testBooksController() throws Exception {
        Books b1 = new Books("b1");
        Books b2 = new Books("b2");
        List<Books> booksList = Arrays.asList(b1, b2);
        
        when(bookRepository.findAll()).thenReturn(booksList);
        List<Books> response = booksController.getBooks();
        System.out.println(response);
        
        assertEquals(2, response.size());
    }
}

References:

viveksb007
  • 61
  • 5