1.概述

Java 8推出了一系列新的,很棒的功能,如Lambda和Streams。而且自然而然,米科蒂托利用了最近的创新第二主要版本

在本文中,我们将探讨这种强大的组合提供的一切。

2.用默认方法模拟界面

从Java 8开始,我们现在可以在我们的接口中编写方法实现。这可能是一个很好的新功能,但它对语言的介绍违反了自概念以来是Java的一部分。

Mockito版本1还没有准备好这种变化。基本上,因为它不允许我们要求它从接口调用真实方法。

想象一下,我们有一个带有2方法声明的接口:第一个是我们都习惯的旧方法签名,另一个是一个全新的默认方法:

公共接口JobService {可选 findcurrentjobposition(person phare);默认布尔分配约会(人员,jobposition jobposition){if(!findcurrentjobpobposition(person).ispresent()){person.setcurrentjobpobposition(JobPosition);返回真;}否则{返回false;}}}

请注意ensignjobposition()默认方法有一个呼叫未实现的findcurrentjobposition()方法。

现在,假设我们想测试我们的实施ensignjobposition()没有写实际实现findcurrentjobposition()。我们可以简单地创建一个嘲弄的版本jobservice,然后告诉Mockito从呼叫到我们未实现的方法返回已知值,并调用真实方法ensignjobposition()叫做:

公共类jobserviceunittest {@mock private jobservice作业;@test public void givendefaultmethod_whencallrealmethod_thennoexceptionisraise(){person person = new person();(jobservice.findcurrentjobposition(person)).thenreturn(可选.of(新的jobposition()));docallrealmethod()。当(jobservice).assignjobposition(mockito.any(person.class),mockito.any(JobPosition.Class));assertfalse(jobservice.assignjobposition(person,new bobposition())));}}

这是完全合理的,因为我们使用抽象类而不是一个接口,它就可以正常工作。

然而,Mockito 1的内部工作只是没有为此结构做好准备。如果我们使用Mockito Pre版本2运行此代码,我们将获得这种良好的描述错误:

org.mockito.exceptions.base.mockitoException:无法在Java接口上调用真正的方法。界面没有任何实现!只有在嘲笑混凝土类时才能调用真实方法。

Mockito正在进行它的工作并告诉我们,它无法在接口上调用真正的方法,因为此操作在Java 8之前是不可想象的。

好消息是,只需改变Mockito的版本,我们可以使用我们可以使这个错误消失。例如,使用Maven,我们可以使用版本2.7.5(可以找到最新的Mockito版本这里):

<依赖项>  org.mockito   Mockito-Core   2.7.5   test  

没有必要对代码进行任何更改。下次我们运行测试时,将不再发生错误。

3.返回默认值可选的溪流

可选的溪流是其他Java 8新增添加。两个类之间的一个相似性是两者都具有代表空对象的特殊类型。此空对象使其更容易避免到目前为止的全能空指针异常

3.1。例子可选的

考虑注入的服务JobService.在上一节中描述并具有调用的方法jobservice#findcurrentjobposition()

公共类别失业iceimpl实施unementsmentservice {private jobservice jobservice;公共失程门工业iceimpl(jobservice作业操作){this.jobservice = jobservice;@Override公共布尔思人人物lextitledtouneMployMenseUpport(Person Person){可选可选= JobService.findCurrentJobPosition(person);返回!optional.ispresent();}}

现在,假设我们想创建一个测试来检查,当一个人没有当前的工作岗位时,他们有权获得失业支持。

在这种情况下,我们会迫使findcurrentjobposition()返回空可选的在Mockito 2之前,我们需要将呼叫模拟到该方法:

公共类unemploymentserviceimplunittest {@mock private jobservice作业操作;@injectmocks私人失业iceimpl失业;@test public voidedreturnisoftypeoptional_whenmocked_thenvalueisempty(){person person = new person();(jobservice.findcurrentjobpobposition(domets.class))).thenreturn(可选。•空白());asserttrue(unementservice.personisentititledtounedmentsupport(person));}}

当(...).thenreturn(...)第13行的指令是必要的,因为Mockito对任何方法调用的默认返回值都调用了模拟对象空值。版本2改变了这种行为。

由于我们很少在处理时处理空值可选的,Mockito现在返回一个空可选的默认。这是与呼叫返回的完全相同的价值可选..空白()

所以,使用Mockito版本2,我们可以摆脱第13行,我们的测试仍然是成功的:

公共类unemploymentserviceimplunittest {@test public voidedreturnisoptional_whendefaultvalueisreturned_thenvalueisempty(){person person = new person();asserttrue(unementservice.personisentititledtounedmentsupport(person));}}

3.2。例子溪流

当我们模拟返回a的方法时,会发生相同的行为溪流

让我们为我们的新方法添加新方法JobService.返回代表一个人曾经工作过的所有作业位置的流的界面:

公共接口JobService {Stream  ListJobs(人员);}

如果一个人在与给定搜索字符串匹配的作业上,则此方法将用于查询的另一个新方法:

公共类UnemplaymentserviceImpl实现unementalmentservice {@override public可选 searchjob(person person,string searchstring){return作业服务.listjobs(person).filter((j) - > j.gettitle()。包含(searchstring)).findfirst();}}

所以,假设我们想要正确测试实现searchjob(),不必担心写作金宝搏官网188belistjobs()并假设我们希望在该人尚未在任何工作中工作时测试这些方案。在这种情况下,我们会想要的listjobs()返回空溪流

在Mockito 2之前,我们需要嘲笑呼叫listjobs()写下这样的测试:

公共类unemploymentserviceimplunittest {@test public voidedreturnisoftypestream_whenmocked_thenvalueisempty(){person person = new person();(jobservice.listjobs(任何(person.class)))。然后return(stream.empty());assertfalse(Unemmentservice.searchJob(Person,“).ispresent());}}

如果我们升级到版本2,我们可以放弃当(...).thenreturn(...)打电话,因为现在Mockito将返回一个空的溪流默认情况下的嘲弄方法

公共类unemploymentserviceimplunittest {@test public voidedreturnisstream_whendefaultvalueisreturned_thenvalueisempty(){person person = new person();assertfalse(Unemmentservice.searchJob(Person,“).ispresent());}}

4.利用Lambda表达

使用Java 8的Lambda表达式,我们可以使陈述更紧凑,更易于阅读。在使用Mockito时,Lambda表达式带来的简单性的2个非常好的例子ArgumentMatchers.和习俗答案

4.1。λ和ArgumentMatcher.

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

使用Java 8,我们可以用简单的Lambda表达式替换内部类:

公共类ArgumentMatcherWithLambdaUnittest {@test公共void wherspersonwithjob_thenisnotentitled(){人彼得=新人(“彼得”);人Linda =新人(“琳达”);JobPosition老师=新的Jobposition(“老师”);什么时候(jobservice.findcurrentjobposition(ArgumentMatchers.argthat(p  - > p.getname()。等于(“Peter”)))).thenreturn(可选.Of(教师));asserttrue(unementservice.personisentititledtounemploymentsupport(Linda));assertfalse(unementsmentservice.personisentititledtounemploymentsupport(彼得));}}

4.2。λ和习俗的组合回答

在将Lambda表达式与Mockito的表达式结合时,可以实现相同的效果回答

例如,如果我们想模拟呼叫listjobs()方法以使其返回一个溪流包含一个单一的工作职位如果是姓名是“彼得”,还有空溪流否则,我们必须创建一个实现的类(匿名或内部)回答界面。

再次使用Lambda表达式,允许我们在内联编写所有模拟行为:

公共类sudateanswerwithlambdaunittest {@before public void init(){何时(jobservice.listjobs(任何(person.class)))。然后((i) - > stream.of(新的jobosition(“教师”)).filter(p- >((人)i.getargument(0))。getName()。等于(“彼得”)));}}

请注意,在上面的实施中,没有必要伙伴内班。

结论

在本文中,我们涵盖了如何利用新的Java 8和Mockito 2功能,以写入清洁,更简单,更短的代码。如果您不熟悉我们在此处看到的一些Java 8功能,请查看我们的一些文章:

此外,请检查我们的随附的代码github存储库

通用底部

使用Spring 5和Spring Boot 2开始,通过学习春天课程:

>>查看课程
评论在本文上关闭!