java 使用 Mockito 2.0.7 模拟 lambda 表达式

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30081357/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 16:25:25  来源:igfitidea点击:

Use Mockito 2.0.7 to mock lambda expressions

javaunit-testingjunitlambdamockito

提问by Christoph

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 @Beforemethod looks like this:

我的@Before方法是这样的:

@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

java.util.NoSuchElementException:不存在值

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

当我双击错误时,它指向.get()第一个 lambda的方法。

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

你们中有人成功模拟了 lambda 表达式并知道我如何解决我的问题吗?

回答by Alex Wittig

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

没有必要模拟这么深的调用。简单地模拟personRepo.findAll()并让 Streaming API 正常工作:

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))))

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

just set/mock emailon your Personobjects to be the expected value.

只需将email您的Person对象设置/模拟为预期值。

Alternatively, consider implementing PersonRepo.findByEmail.

或者,考虑实施PersonRepo.findByEmail.

回答by Jeff Bowman

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_STUBSanswer(if put on personRepo) would save and return stub objects where applicable, each call to whenwill itself stub exactly one call.

首先,您试图模拟五个不同方法调用的链。Mockito 不能很好地处理这个问题。尽管RETURNS_DEEP_STUBS答案(如果放在 personRepo 上)会在适用的情况下保存并返回存根对象,但每次调用都when将存根一次调用。

Second, Mockito matchers aren't flexible enough to work deeply in calls; calls to whenshould contain exactly one method call without chaining, and calls to Mockito matchers like anyshould 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.

其次,Mockito 匹配器不够灵活,无法在调用中深入工作;调用when应该只包含一个没有链接的方法调用,并且像 Mockito 匹配器这样的调用any应该正好代表该方法中的一个参数。你拥有它的方式,你正在创建一个谓词,p -> (p.getEmail().equals(null))并在堆栈上留下一个匹配器,以便稍后打破它。

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

使用Alex Wittig 的答案来解决这个问题,并注意在以后的问题中正确使用匹配器和存根。