Mockito’s Java 8 Features – Mockito’的Java 8功能

最后修改: 2017年 3月 5日

1. Overview


Java 8 introduced a range of new, awesome features, like lambda and streams. And naturally, Mockito leveraged these recent innovations in its 2nd major version.

Java 8引入了一系列新的、令人敬畏的功能,如lambda和流。当然,Mockito也在其第二大版本中利用了这些最新的创新。

In this article, we are going to explore everything this powerful combination has to offer.


2. Mocking Interface With a Default Method


From Java 8 onwards we can now write method implementations in our interfaces. This might be a great new functionality, but its introduction to the language violated a strong concept that was part of Java since its conception.

从Java 8开始,我们现在可以在我们的接口中编写方法实现。这可能是一个很好的新功能,但它的引入违反了一个强大的概念,这个概念从Java的概念开始就是它的一部分。

Mockito version 1 was not ready for this change. Basically, because it didn’t allow us to ask it to call real methods from interfaces.


Imagine that we have an interface with 2 method declarations: the first one is the old-fashioned method signature we’re all used to, and the other is a brand new default method:


public interface JobService {
    Optional<JobPosition> findCurrentJobPosition(Person person);
    default boolean assignJobPosition(Person person, JobPosition jobPosition) {
        if(!findCurrentJobPosition(person).isPresent()) {
            return true;
        } else {
            return false;

Notice that the assignJobPosition() default method has a call to the unimplemented findCurrentJobPosition() method.

请注意,assignJobPosition() default方法有一个对未实现的findCurrentJobPosition() 方法的调用。

Now, suppose we want to test our implementation of assignJobPosition() without writing an actual implementation of findCurrentJobPosition(). We could simply create a mocked version of JobService, then tell Mockito to return a known value from the call to our unimplemented method and call the real method when assignJobPosition() is called:


public class JobServiceUnitTest {
    private JobService jobService;

    public void givenDefaultMethod_whenCallRealMethod_thenNoExceptionIsRaised() {
        Person person = new Person();

              .thenReturn(Optional.of(new JobPosition()));


        assertFalse(jobService.assignJobPosition(person, new JobPosition()));

This is perfectly reasonable and it would work just fine given we were using an abstract class instead of an interface.


However, the inner workings of Mockito version 1 were just not ready for this structure. If we were to run this code with Mockito pre version 2 we would get this nicely described error:


Cannot call a real method on java interface. The interface does not have any implementation!
Calling real methods is only possible when mocking concrete classes.

Mockito is doing its job and telling us it can’t call real methods on interfaces since this operation was unthinkable before Java 8.

Mockito正在做它的工作,告诉我们它不能调用接口上的真实方法,因为这种操作在Java 8之前是不可想象的。

The good news is that just by changing the version of Mockito we’re using we can make this error go away. Using Maven, for example, we could use version 2.7.5 (the latest Mockito version can be found here):



There is no need to make any changes to the code. The next time we run our test, the error will no longer occur.


3. Return Default Values for Optional and Stream


Optional and Stream are other Java 8 new additions. One similarity between the two classes is that both have a special type of value that represent an empty object. This empty object makes it easier to avoid the so far omnipresent NullPointerException.

OptionalStream是其他Java 8新增加的功能。这两个类的一个相似之处是,都有一个特殊类型的值,代表一个空对象。这个空对象使我们更容易避免迄今为止无处不在的NullPointerException.

3.1. Example With Optional


Consider a service that injects the JobService described in the previous section and has a method that calls JobService#findCurrentJobPosition():


public class UnemploymentServiceImpl implements UnemploymentService {
    private JobService jobService;
    public UnemploymentServiceImpl(JobService jobService) {
        this.jobService = jobService;

    public boolean personIsEntitledToUnemploymentSupport(Person person) {
        Optional<JobPosition> optional = jobService.findCurrentJobPosition(person);
        return !optional.isPresent();

Now, assume we want to create a test to check that, when a person has no current job position, they are entitled to the unemployment support.


In that case, we would force findCurrentJobPosition() to return an empty Optional. Before Mockito version 2, we were required to mock the call to that method:

在这种情况下,我们将强制findCurrentJobPosition() 返回一个空的Optional在Mockito第2版之前,我们需要对该方法的调用进行模拟。

public class UnemploymentServiceImplUnitTest {
    private JobService jobService;

    private UnemploymentServiceImpl unemploymentService;

    public void givenReturnIsOfTypeOptional_whenMocked_thenValueIsEmpty() {
        Person person = new Person();


This when(…).thenReturn(…) instruction on line 13 is necessary because Mockito’s default return value for any method calls to a mocked object is null. Version 2 changed that behavior.


Since we rarely handle null values when dealing with Optional, Mockito now returns an empty Optional by default. That is the exact same value as the return of a call to Optional.empty().

由于我们在处理Optional时很少处理空值,Mockito现在默认返回一个空的Optional 。这与调用Optional.empty()的返回值完全相同。

So, when using Mockito version 2, we could get rid of line 13 and our test would still be successful:


public class UnemploymentServiceImplUnitTest {
    public void givenReturnIsOptional_whenDefaultValueIsReturned_thenValueIsEmpty() {
        Person person = new Person();

3.2. Example With Stream


The same behavior occurs when we mock a method that returns a Stream.


Let’s add a new method to our JobService interface that returns a Stream representing all the job positions that a person has ever worked at:


public interface JobService {
    Stream<JobPosition> listJobs(Person person);

This method is used on another new method that will query if a person has ever worked on a job that matches a given search string:


public class UnemploymentServiceImpl implements UnemploymentService {
    public Optional<JobPosition> searchJob(Person person, String searchString) {
        return jobService.listJobs(person)
          .filter((j) -> j.getTitle().contains(searchString))

So, assume we want to properly test the implementation of searchJob(), without having to worry about writing the listJobs() and assume we want to test the scenario when the person hasn’t work at any jobs yet. In that case, we would want listJobs() to return an empty Stream.


Before Mockito version 2, we would need to mock the call to listJobs() to write such test:


public class UnemploymentServiceImplUnitTest {
    public void givenReturnIsOfTypeStream_whenMocked_thenValueIsEmpty() {
        Person person = new Person();
        assertFalse(unemploymentService.searchJob(person, "").isPresent());

If we upgrade to version 2, we could drop the when(…).thenReturn(…) call, because now Mockito will return an empty Stream on mocked methods by default:


public class UnemploymentServiceImplUnitTest {
    public void givenReturnIsStream_whenDefaultValueIsReturned_thenValueIsEmpty() {
        Person person = new Person();
        assertFalse(unemploymentService.searchJob(person, "").isPresent());

4. Leveraging Lambda Expressions


With Java 8’s lambda expressions we can make statements much more compact and easier to read. When working with Mockito, 2 very nice examples of the simplicity brought in by lambda expressions are ArgumentMatchers and custom Answers.

通过Java 8的lambda表达式,我们可以使语句更紧凑,更容易阅读。在使用Mockito时,羔羊表达式带来的两个非常好的例子是ArgumentMatchers和自定义Answers

4.1. Combination of Lambda and ArgumentMatcher


Before Java 8, we needed to create a class that implemented ArgumentMatcher, and write our custom rule in the matches() method.

在Java 8之前,我们需要创建一个实现ArgumentMatcher的类,并在matches()方法中编写我们的自定义规则。

With Java 8, we can replace the inner class with a simple lambda expression:

在Java 8中,我们可以用一个简单的lambda表达式来代替内层类。

public class ArgumentMatcherWithLambdaUnitTest {
    public void whenPersonWithJob_thenIsNotEntitled() {
        Person peter = new Person("Peter");
        Person linda = new Person("Linda");
        JobPosition teacher = new JobPosition("Teacher");

          ArgumentMatchers.argThat(p -> p.getName().equals("Peter"))))

4.2. Combination of Lambda and Custom Answer


The same effect can be achieved when combining lambda expressions with Mockito’s Answer.


For example, if we wanted to simulate calls to the listJobs() method in order to make it return a Stream containing a single JobPosition if the Person‘s name is “Peter”, and an empty Stream otherwise, we would have to create a class (anonymous or inner) that implemented the Answer interface.

例如,如果我们想模拟对listJobs()方法的调用,以使它在Person的名字是 “Peter “的情况下返回一个包含单个JobPositionStream,否则返回一个空Stream,我们将不得不创建一个实现Answer接口的类(匿名或内部)。

Again, the use of a lambda expression, allow us to write all the mock behavior inline:


public class CustomAnswerWithLambdaUnitTest {
    public void init() {
        when(jobService.listJobs(any(Person.class))).then((i) ->
          Stream.of(new JobPosition("Teacher"))
          .filter(p -> ((Person) i.getArgument(0)).getName().equals("Peter")));

Notice that, in the implementation above, there is no need for the PersonAnswer inner class.


5. Conclusion


In this article, we covered how to leverage new Java 8 and Mockito version 2 features together to write cleaner, simpler and shorter code. If you are not familiar with some of the Java 8 features we saw here, check some of our articles:

在这篇文章中,我们介绍了如何利用Java 8和Mockito第2版的新特性来编写更干净、更简单、更短的代码。如果你不熟悉我们在这里看到的一些Java 8特性,请查看我们的一些文章。

Also, check the accompanying code on our GitHub repository.