1.Overview.

通常,提供的默认设置5对于我们的模拟对象应该超过足够的。

然而,可能有时需要在模拟创建期间提供额外的模拟设置。这在调试、处理遗留代码或覆盖一些极端情况时可能很有用。

在上一个教程中,我们学会了如何与之合作仁慈的模拟。在这个快速教程中,我们将学习如何使用其他一些有用的特性模仿接口提供。

2.模拟设置

简单地说,模仿界面提供A.流利的API这允许我们在模拟创建期间轻松添加和组合其他模拟设置。

当我们创建模拟对象时,我们所有的模型都携带一组默认设置。让我们来看看一个简单的模拟示例:

列表模型列表=模拟(list.class);

幕后的景色模拟方法委派给另一个重载的方法,为我们的模拟带来了一组默认设置:

公共静态 t mock(class  classtomock){return mock(classtomock,withsettings());}

让我们看看我们的默认设置:

公共静态模块iteSettings(){返回新MockSettingsimpl()。defaultanswer(returns_defaults);}

正如我们所看到的,我们模拟对象的标准设置设置非常简单。我们为模拟交互配置默认答案。通常,使用returns_defaults.将返回一些空值。

从此带走的重要点是,如果需要,我们可以向我们的模拟对象提供自己的自定义设置

在下一节中,我们将看到一些例子,说明这可能在什么时候会派上用场。

3.提供一个不同的默认答案

现在我们对模拟设置有了更多的了解,让我们看看如何更改模拟对象的默认返金宝搏官网188be回值。

让我们想象一下,我们有一个非常简单的模拟:

PizzaService service = mock(PizzaService.class);披萨披萨= service.orderHouseSpecial();PizzaSize size = pizza.getSize();

当我们按预期运行此代码时,我们将得到NullPointerException因为我们的未掌控的方法OrderHousSpecial.回报

这没关系,但有时在使用遗留代码时,我们可能需要处理模拟对象的复杂层次结构,并且可以耗时以定位出现这些类型的异常情况。

帮助我们打击这一点,我们可以通过Mock创建期间的模拟设置提供不同的默认答案

pizzaservice pizzaservice = mock(pizzaservice.class,withsettings()。defaultanswer(returns_smart_nulls));

通过使用returns_smart_nulls.作为我们的默认答案,Mockito为我们提供了一个更加有意义的错误消息,可以确切地向我们显示错误的存根时:

org.mockito.exceptions.verification.MartNullPointerException:您在此处拥有一个nullpointerException: - >在com.baeldung.moc金宝搏188体育kito.mocksettings.mocksettingsunittest.whenservicemockedwithsmartnulls_thenexceptionhasextrainfo(mocksettingsunittest.java:45),因为此方法调用是*不是正确的*  - >在com.ba金宝搏188体育eldung.mockito.mocksettings.mocksettingsunittest.whenservicemockedwithsmartnulls_thenexceptionhasextrainfo(mocksettingsunittest.java:44)pizzaservice.orderhourespecial();

这确实可以在调试测试代码时节省一些时间。的答案枚举还提供一些其他预配置的模拟答案:

  • RETURNS_DEEP_STUBS-返回的答案深茬-使用流利的API时,这可能很有用
  • returns_mocks.-使用此答案将返回普通值,如空集合或空字符串,然后,它试图返回mock
  • calls_real_methods.- 当姓名建议时,当我们使用此实现时,将委派方法将委托为实际实现

4.命名模拟和详细日志记录

我们可以通过使用撰写我们的嘲笑名称的名字的方法模仿。这对于调试特别有用,因为我们提供的名称在所有验证错误中都使用:

PizzaService服务= mock(PizzaService.class, withSettings() .name("pizzaServiceMock") .verboseLogging() .defaultAnswer(RETURNS_SMART_NULLS));

在本例中,我们通过使用方法将此命名特性与详细日志记录结合起来verboseLogging ()

使用此方法可以实时记录到此模拟的方法调用的标准输出流。。同样,可以在测试调试期间使用它,以便发现与mock的错误交互。

当我们运行我们的测试时,我们将在控制台上看到一些输出:

pizzaServiceMock.orderHouseSpecial ();->在com. baeldung.mo金宝搏188体育ckito.mocksettingsunittest . whenservicemockedwithnameandverboselogging_thenlogsmethodinvocations (MockSettingsUnitTest.java:36)已经返回:“Mock for Pizza, hashCode: 366803687”(com.baeldung.mockito.fluentapi.Pizza$MockitoMock$168951489)

如果我们使用的话,它很有意思@嘲笑注释后,我们的模拟自动使用字段名作为模拟名。

5.嘲笑额外的界面

偶尔,我们可能需要指定额外的界面我们的模拟应该实现。同样,在使用我们无法重构的遗留代码时,这可能是有用的。

假设我们有一个特殊的接口:

公共界面专用接口{//公共方法}

以及使用此界面的类:

公共类SimpleService {public simpleService(specialInterface special){runnable runnable =(runnable)特殊;runnable.run();} //更多服务方法}

当然,这不是干净代码,但如果我们被迫为此编写单元测试,我们很可能会遇到问题:

SpecialInterface specialMock = mock(SpecialInterface.class);SimpleService service = new SimpleService(specialMock);

当我们运行这段代码时,我们将得到ClassCastException为了纠正这一点,我们可以使用多种类型使用多种类型的模拟extraInterfaces方法

SpecialInterface specialMock = mock(SpecialInterface.class, withSettings() .extraInterfaces(Runnable.class));

现在,我们的模拟创建代码不会失败,但我们应该真正强调,强制转换为未声明的类型并不酷。

6.提供构造函数参数

在这个最后一个例子中,我们会看到我们如何使用模仿调用具有参数值的真实构造函数:

@test public void whenmocksetupwithconstructor_thenconstructorisinvoked(){appristrationcoffee coffeespy = mock(apprist offoffee.class,withsettings().useconstructor(“espresso”).defaultanswer(calls_real_methods));assertequals(“咖啡名:”,“espresso”,coffeespy.getname());}

这次,Mockito尝试使用构造函数细绳的实例时抽象特征嘲笑。我们还将默认答案配置为委派给实际实现。

如果我们在构造函数中有一些逻辑,我们希望测试或触发这些逻辑以使我们的类处于某个特定状态,那么这可能会很有用。它也很有用间谍在抽象课上。

7.结论

在这个快速教程中,我们已经看到了如何使用附加的模拟设置创建模拟。

然而,我们应该重申,尽管这有时是有用的,而且可能是不可避免的,但在大多数情况下,我们应该努力使用简单的模拟编写简单的测试。

一如既往,可以使用文章的完整源代码在GitHub

通用底部

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

>>看看这个课程
对这篇文章的评论关闭!