title: WrongTypeOfReturnValue error while unit testing
body: <p>I migrated to Spring 2.X from 1.X and some errors occured. I can not handle this one.</p>
  
  <p>(EDIT BELOW)</p>
  
  <p>I tried both with <code>when...</code> and with <code>doReturn</code> , none of these works.</p>
  
  <p>Method I want to unit-test:</p>
  
  <pre><code>@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(() -&gt; new IllegalArgumentException("Account does not exist!"));
  
          if (account.getAmountOfCashToPay() == 0) {
              if (bookRepository.doesBookExistsWithGivenID(bookID)) {
                  Book bookToRent = bookRepository.findById(bookID)
                          .orElseThrow(() -&gt; 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";
      }
  </code></pre>
  
  <p>Unit-test</p>
  
  <pre><code>@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()));
  }
  }
  </code></pre>
  
  <p>Stacktrace:</p>
  
  <pre><code>java.lang.Exception: Unexpected exception, expected&lt;java.lang.IllegalArgumentException&gt; but was&lt;org.mockito.exceptions.misusing.WrongTypeOfReturnValue&gt;
  
  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
  </code></pre>
  
  <p><strong>//EDIT</strong>
  With Timothy some help. Code looks like this.</p>
  
  <pre><code>@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());
      }
  </code></pre>
  
  <p>and Stack:</p>
  
  <pre><code>java.lang.Exception: Unexpected exception, expected&lt;java.lang.IllegalArgumentException&gt; but was&lt;org.mockito.exceptions.misusing.WrongTypeOfReturnValue&gt;
  
      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
  </code></pre>