简体   繁体   English

如何在Mockito单元测试中摆脱NullPointerException

[英]How to get rid of NullPointerException in Mockito unit test

I want to unit test rentBook method that is rensposible for renting. 我想对可租用的rentBook方法进行单元测试。

Here is the @Service 这是@Service

package bookrental.service.book.rentals;

import bookrental.model.account.User;
import bookrental.model.book.Book;
import bookrental.model.book.BookRentals;
import bookrental.repository.account.UserRepository;
import bookrental.repository.book.BookRepository;
import bookrental.repository.book.BookRentalsRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class BookRentalService {

    private final UserRepository userRepository;
    private final BookRepository bookRepository;
    private final BookRentalsRepository bookRentalsRepository;

    @Autowired
    public BookRentalService(BookRepository bookRepository, BookRentalsRepository bookRentalsRepository, UserRepository userRepository) {
        this.bookRepository = bookRepository;
        this.bookRentalsRepository = bookRentalsRepository;
        this.userRepository = userRepository;
    }

    public String rentBook(int userID, int bookID) {
        if (userRepository.doesAccountExistsWithGivenID(userID)) {
            if (bookRepository.doesBookExistsWithGivenID(bookID)) {
                Book bookToRent = bookRepository.findOne(bookID);
                if (bookToRent.isAvailable()) {
                    updateBookAvailabilityAndSaveToDb(bookToRent);
                    BookRentals preparedBookToRent = prepareBookToRent(userID, bookID);
                    bookRentalsRepository.save(preparedBookToRent);
                } else {
                    throw new IllegalArgumentException("Book is not available");
                }
            } else {
                throw new IllegalArgumentException("Book does not exist!");
            }
        } else {
            throw new IllegalArgumentException("Account does not exist!");
        }
        return "Book was rented";
    }

    private BookRentals prepareBookToRent(int userID, int bookID) {
        return new BookRentals(new Book(bookID), new User(userID));
    }

    private void updateBookAvailabilityAndSaveToDb(Book bookToRent) {
        bookToRent.setAvailable(false);
        bookRepository.save(bookToRent);
    }

    public List<BookRentals> findAllRentals() {
        List<BookRentals> rentedBooks = new ArrayList<>();
        bookRentalsRepository.findAll().forEach(rentedBooks::add);
        return rentedBooks;
    }
}

I tried to unit test it, but getting NPE. 我试图对其进行单元测试,但获得了NPE。 I do not know what I am doing wrong. 我不知道我在做什么错。

package bookrental.service.book.rentals;

import bookrental.model.account.User;
import bookrental.model.book.Book;
import bookrental.model.book.BookRentals;
import bookrental.repository.book.BookRentalsRepository;
import bookrental.repository.book.BookRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import static org.junit.Assert.*;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class BookRentalServiceTest {

    @Mock
    BookRentalsRepository bookRentalsRepository;
    @Mock
    BookRepository bookRepository;

    @InjectMocks
    BookRentalService bookRentalService;

    @Test
    public void rentBook() {
        Book book = createDummyBook();
        User user = createDummyUser();
        BookRentals bookToRent = createDummyRentedBook(user, book);

       when(bookRentalsRepository.save(bookToRent)).thenReturn(bookToRent);

        bookRentalService.rentBook(user.getId(), book.getId());

        verify(bookRentalsRepository).save(bookToRent);
        verify(bookRentalService, times(1)).rentBook(user.getId(), book.getId());
    }

    @Test
    public void findAllRentals() {
    }

    private Book createDummyBook() {
        return new Book(0, "W pustyni i w puszczy", "Henryk Sienkiewicz", "dramat", true);
    }

    private BookRentals createDummyRentedBook(User user, Book book) {
        return new BookRentals(book, user);
    }

    private User createDummyUser() {
        return new User(0, "must", "123");
    }
}

Stacktrace: 堆栈跟踪:

java.lang.NullPointerException
    at bookrental.service.book.rentals.BookRentalService.rentBook(BookRentalService.java:30)
    at bookrental.service.book.rentals.BookRentalServiceTest.rentBook(BookRentalServiceTest.java:38)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37)
    at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    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)

/// EDIT ///编辑

@Test
    public void rentBook() {
        Book book = createDummyBook();
        User user = createDummyUser();
        BookRentals bookToRent = createDummyRentedBook(user, book);

        when(userRepository.doesAccountExistsWithGivenID(user.getId())).thenReturn(true);
        when(bookRepository.doesBookExistsWithGivenID(book.getId())).thenReturn(true);
        when(bookRepository.findOne(book.getId())).thenReturn(book);
        when(userRepository.findOne(user.getId())).thenReturn(user);

        String expected = "Book was rented";

        assertEquals(expected, bookRentalService.rentBook(user.getId(), book.getId()));

        verify(bookRentalsRepository, times(1)).save(bookToRent);
    }

STACKTRACE : 堆栈跟踪

Argument(s) are different! Wanted:
bookRentalsRepository.save(
    bookrental.model.book.BookRentals@7574b32f
);
-> at bookrental.service.book.rentals.BookRentalServiceTest.rentBook(BookRentalServiceTest.java:48)
Actual invocation has different arguments:
bookRentalsRepository.save(
    bookrental.model.book.BookRentals@1c62c511
);
-> at bookrental.service.book.rentals.BookRentalService.rentBook(BookRentalService.java:36)

Comparison Failure:  <Click to see difference>

Argument(s) are different! Wanted:
bookRentalsRepository.save(
    bookrental.model.book.BookRentals@7574b32f
);
-> at bookrental.service.book.rentals.BookRentalServiceTest.rentBook(BookRentalServiceTest.java:48)
Actual invocation has different arguments:
bookRentalsRepository.save(
    bookrental.model.book.BookRentals@1c62c511
);
-> at bookrental.service.book.rentals.BookRentalService.rentBook(BookRentalService.java:36)

    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:488)
    at bookrental.service.book.rentals.BookRentalServiceTest.rentBook(BookRentalServiceTest.java:48)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37)
    at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    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)

From the stack trace, it seems it fails because you didn't mock also the user repository. 从堆栈跟踪来看,它似乎失败了,因为您没有同时模拟用户存储库。 Add the following: 添加以下内容:

@Mock
UserRepository userRepository;

... ...

when(userRepository.doesAccountExistsWithGivenID(user.getId()).thenReturn(true);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM