Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use Mockito 2.0.7 to mock lambda expressions

I want to mock a query provided on my repository like this:

@Test
public void GetByEmailSuccessful() {
    // setup mocks
    Mockito.when(this.personRepo.findAll()
            .stream()
            .filter(p -> (p.getEmail().equals(Mockito.any(String.class))))
            .findFirst()
            .get())
            .thenReturn(this.personOut);
    Mockito.when(this.communityUserRepo.findOne(this.communityUserId))
            .thenReturn(this.communityUserOut);
...

My @Before method looks like this:

@Before
public void initializeMocks() throws Exception {
    // prepare test data.
    this.PrepareTestData();

    // init mocked repos.
    this.personRepo = Mockito.mock(IPersonRepository.class);
    this.communityUserRepo = Mockito.mock(ICommunityUserRepository.class);
    this.userProfileRepo = Mockito.mock(IUserProfileRepository.class);
}

Sadly when I run the test I receive the error:

java.util.NoSuchElementException: No value present

When I double-click the error it points at the .get() method of the first lambda.

Have any of you successfully mocked a lambda expression and know how I can solve my problem?

like image 799
Christoph Avatar asked May 06 '15 15:05

Christoph


2 Answers

There's no need to mock such deep calls. Simply mock personRepo.findAll() and let the Streaming API work as normal:

Person person1 = ...
Person person2 = ...
Person person3 = ...
List<Person> people = Arrays.asList(person1, person2, ...);
when(personRepo.findAll()).thenReturn(people);

And then instead of

.filter( p -> (p.getEmail().equals(Mockito.any(String.class))) )

just set/mock email on your Person objects to be the expected value.

Alternatively, consider implementing PersonRepo.findByEmail.

like image 154
Alex Wittig Avatar answered Oct 21 '22 18:10

Alex Wittig


Two things:

Mockito.when(this.personRepo.findAll()
      .stream()
      .filter(p -> (p.getEmail().equals(Mockito.any(String.class))))
      .findFirst()
      .get())
    .thenReturn(this.personOut);

First, you're trying to mock a chain of five different method calls. Mockito doesn't handle this very well; though the RETURNS_DEEP_STUBS answer (if put on personRepo) would save and return stub objects where applicable, each call to when will itself stub exactly one call.

Second, Mockito matchers aren't flexible enough to work deeply in calls; calls to when should contain exactly one method call without chaining, and calls to Mockito matchers like any should stand in for exactly one of the arguments in that method. The way you have it, you're creating a predicate p -> (p.getEmail().equals(null)) and leaving a matcher on the stack to break things later.

Use Alex Wittig's answer to solve this problem, and be mindful of stubbing and using matchers correctly in future problems.

like image 20
Jeff Bowman Avatar answered Oct 21 '22 19:10

Jeff Bowman