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 groupID> Mockito-Core ARTIFACTID> 2.7.5 version> test scope> 依赖项>
没有必要对代码进行任何更改。下次我们运行测试时,将不再发生错误。
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存储库。