单元测试时出现WrongTypeOfReturnValue错误

时间:2018-12-26 23:10:53

标签: java unit-testing junit mockito

我从1.X迁移到Spring 2.X,发生了一些错误。我不能处理这个。

(下面编辑)

我同时尝试了when...doReturn,但这些方法均无效。

我要进行单元测试的方法:

@Service
public class BookRentalService {

    private final AccountRepository accountRepository;
    private final BookRepository bookRepository;
    private final BookRentalsRepository bookRentalsRepository;

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

public String rentBook(int accountID, int bookID) {
        Account account = accountRepository.findById(accountID)
                .orElseThrow(() -> new IllegalArgumentException("Account does not exist!"));

        if (account.getAmountOfCashToPay() == 0) {
            if (bookRepository.doesBookExistsWithGivenID(bookID)) {
                Book bookToRent = bookRepository.findById(bookID)
                        .orElseThrow(() -> new IllegalArgumentException("Book does not exist!"));

                if (bookToRent.isAvailable()) {
                    updateBookAvailabilityAndSaveToDb(bookToRent);
                    BookRentals preparedBookToRent = prepareBookToRent(accountID, bookToRent);
                    bookRentalsRepository.save(preparedBookToRent);
                } else {
                    throw new IllegalArgumentException("Book is not available");
                }
            }
        } else {
            throw new IllegalArgumentException("Please go to paypenalty/accountID to settle the arrears, otherwise you can not rent more books!");
        }

        return "Book was rented";
    }

单元测试

@RunWith(MockitoJUnitRunner.class)
public class BookRentalServiceTest {

@Mock
public BookRentalsRepository bookRentalsRepository;
@Mock
public BookRepository bookRepository;
@Mock
public AccountRepository userRepository;

@InjectMocks
public BookRentalService bookRentalService;



@Test(expected = IllegalArgumentException.class)
public void rentBookWhenAccountNotExists() {
    Book book = createDummyBook();
    Account user = createDummyUser();

    //when(bookRepository.doesBookExistsWithGivenID(book.getId())).thenReturn(true);
    //when(bookRepository.findById(book.getId()).orElse(null)).thenReturn(book);
    //when(userRepository.doesAccountExistsWithGivenID(user.getId())).thenReturn(false);

    doReturn(book).when(bookRepository).findById(book.getId()).orElse(null);
    doReturn(true).when(bookRepository).doesBookExistsWithGivenID(book.getId());
    doReturn(false).when(userRepository).doesAccountExistsWithGivenID(user.getId());
    String expected = "Account does not exist";

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

Stacktrace:

java.lang.Exception: Unexpected exception, expected<java.lang.IllegalArgumentException> but was<org.mockito.exceptions.misusing.WrongTypeOfReturnValue>

at org.junit.internal.runners.statements.ExpectException.evaluate(ExpectException.java:28)
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.DefaultInternalRunner$1.run(DefaultInternalRunner.java:79)
at org.mockito.internal.runners.DefaultInternalRunner.run(DefaultInternalRunner.java:85)
at org.mockito.internal.runners.StrictRunner.run(StrictRunner.java:39)
at org.mockito.junit.MockitoJUnitRunner.run(MockitoJUnitRunner.java:163)
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)
Caused by: org.mockito.exceptions.misusing.WrongTypeOfReturnValue: 
Book 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.

at bookrental.service.book.rentals.BookRentalServiceTest.rentBookWhenAccountNotExists(BookRentalServiceTest.java:71)
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.internal.runners.statements.ExpectException.evaluate(ExpectException.java:19)
... 18 more

// EDIT 在蒂莫西的帮助下。代码看起来像这样。

@Test(expected = IllegalArgumentException.class)
    public void rentBookWhenAccountNotExists() {
        Book book = createDummyBook();
        Account user = createDummyUser();

        when(bookRepository.doesBookExistsWithGivenID(book.getId())).thenReturn(true);
        when(bookRepository.findById(book.getId()).orElse(null)).thenReturn(book);
        when(userRepository.doesAccountExistsWithGivenID(user.getId())).thenReturn(false);

        //doReturn(book).when(bookRepository).findById(book.getId()).orElse(null);
        //doReturn(true).when(bookRepository).doesBookExistsWithGivenID(book.getId());
        // doReturn(false).when(userRepository).doesAccountExistsWithGivenID(user.getId());

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

和堆栈:

java.lang.Exception: Unexpected exception, expected<java.lang.IllegalArgumentException> but was<org.mockito.exceptions.misusing.WrongTypeOfReturnValue>

    at org.junit.internal.runners.statements.ExpectException.evaluate(ExpectException.java:28)
    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.DefaultInternalRunner$1.run(DefaultInternalRunner.java:79)
    at org.mockito.internal.runners.DefaultInternalRunner.run(DefaultInternalRunner.java:85)
    at org.mockito.internal.runners.StrictRunner.run(StrictRunner.java:39)
    at org.mockito.junit.MockitoJUnitRunner.run(MockitoJUnitRunner.java:163)
    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)
Caused by: org.mockito.exceptions.misusing.WrongTypeOfReturnValue: 
Book 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.

    at bookrental.service.book.rentals.BookRentalServiceTest.rentBookWhenBookNotExist(BookRentalServiceTest.java:53)
    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.internal.runners.statements.ExpectException.evaluate(ExpectException.java:19)
    ... 18 more

1 个答案:

答案 0 :(得分:0)

此行是错误的:

when(booRepository.findById(book.getId())).thenReturn(Optional.of(book));

orElse()不是模拟对象上的方法,而是属于Optional ...的方法。该行应为:

{{1}}