使用Mockito时如何在spring测试中清理模拟

我是Mockito的新手,清理时遇到了一些麻烦。

我曾经使用JMock2进行单元测试。据我所知,JMock2将期望和其他模拟信息保存在一个上下文中,该上下文将针对每种测试方法进行重建。因此,每种测试方法都不会受到其他方法的干扰。

使用JMock2时,我对弹簧测试采用了相同的策略,但我发现我的帖子中使用的策略存在潜在的问题:为每种测试方法重建应用程序上下文,因此会减慢整个测试过程。

我注意到有很多文章建议在spring测试中使用Mockito,我想尝试一下。在我在一个测试用例中编写两个测试方法之前,它工作得很好。每种测试方法单独运行时都通过了测试,如果其中一个测试方法一起运行,则会失败。我推测这是因为模拟信息保留在模拟本身中(因为我看不到JMock中的任何上下文对象),并且模拟(和应用程序上下文)在两种测试方法中均共享。

我通过在@Before方法中添加reset()来解决它。我的问题是处理这种情况的最佳实践是什么(reset()的javadoc说如果需要reset()则代码有异味吗?任何想法表示赞赏,在此先感谢。

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations = {

"file:src/main/webapp/WEB-INF/booking-servlet.xml",

"classpath:test-booking-servlet.xml" })

@WebAppConfiguration

public class PlaceOrderControllerIntegrationTests implements IntegrationTests {

@Autowired

private WebApplicationContext wac;

private MockMvc mockMvc;

@Autowired

private PlaceOrderService placeOrderService;

@Before

public void setup() {

this.mockMvc = webAppContextSetup(this.wac).build();

reset(placeOrderService);// reset mock

}

@Test

public void fowardsToFoodSelectionViewAfterPendingOrderIsPlaced()

throws Exception {

final Address deliveryAddress = new AddressFixture().build();

final String deliveryTime = twoHoursLater();

final PendingOrder pendingOrder = new PendingOrderFixture()

.with(deliveryAddress).at(with(deliveryTime)).build();

when(placeOrderService.placeOrder(deliveryAddress, with(deliveryTime)))

.thenReturn(pendingOrder);

mockMvc.perform(...);

}

@Test

public void returnsToPlaceOrderViewWhenFailsToPlaceOrder() throws Exception {

final Address deliveryAddress = new AddressFixture().build();

final String deliveryTime = twoHoursLater();

final PendingOrder pendingOrder = new PendingOrderFixture()

.with(deliveryAddress).at(with(deliveryTime)).build();

NoAvailableRestaurantException noAvailableRestaurantException = new NoAvailableRestaurantException(

deliveryAddress, with(deliveryTime));

when(placeOrderService.placeOrder(deliveryAddress, with(deliveryTime)))

.thenThrow(noAvailableRestaurantException);

mockMvc.perform(...);

}

回答:

我认为最好在测试方法之后重新设置模拟,因为这意味着确实存在测试期间发生的某些事情需要清除。

如果重置是在测试方法之前完成的,我不确定应该在重置测试之前发生了什么情况?非嘲笑对象呢?是否有原因(也许有)?如果有原因在代码中没有提到它(例如方法名)?等等。

    1. 背景

使用Spring就像放弃对一个类的单元测试; 使用Spring时,您对测试的控制较少: 隔离实例化生命周期

,可以在单元测试中引用一些looked属性。但是,在许多情况下,Spring提供的库和框架不是那么“ 透明

”,为了进行测试,您可以更好地测试整个组件的实际行为,例如使用Spring MVC,Spring Batch等。

设计这些测试要麻烦得多,因为在许多情况下,这迫使开发人员设计

以认真测试生产代码的行为。由于许多开发人员并不了解有关代码在Spring中如何生活的所有细节,因此尝试使用单元测试来测试类可能会引起很多意外。

但是麻烦仍然存在,测试应该快而小,以向开发人员提供 快速反馈

(例如Infinitest之类的IDE插件非常有用),但是使用Spring进行的测试本质上更慢并且消耗更多的内存。这样一来,它们运行的​​频率就会降低,甚至完全避免在本地工作站上运行它们,以便以后在CI服务器上发现它们发生故障。

2. Mockito和Spring的生命周期

因此,当为子系统设计 时,您最终会得到很多对象,并且显然还有协作者,这些对象可能被嘲笑了。生命周期由Spring

Runner控制,但Mockito模拟不是。因此,您必须自己管理模拟生命周期。

关于Spring

Batch项目期间的生命周期,我们再次遇到了一些对非模拟的残留影响的问题,因此我们有两种选择,每个测试类只能使用一种测试方法,或者使用肮脏的上下文技巧:@DirtiesContext(classMode=ClassMode.AFTER_EACH_TEST_METHOD)。这导致测试速度变慢,内存消耗增加,但这是我们的最佳选择。使用此技巧,您不必重置Mockito模拟。

我对该项目不太了解,但是springockito可以为您提供有关生命周期的一些帮助。该注释子项目似乎更好:它似乎让Spring管理bean的生命周期在Spring容器中,并让测试控制是如何被使用嘲弄。我仍然没有使用此工具的经验,因此可能会有惊喜。

作为免责声明,我非常喜欢Spring,它提供了许多出色的工具来简化其他框架的使用,可以提高生产力,可以帮助设计,但是就像人类发明的每一种工具一样,总会有一个粗糙的边缘(如果不是更多的话…

)。

附带说明一下,有趣的是,这个问题恰好发生在 上下文中,因为JUnit实例化每个测试方法的测试类。如果测试是基于

则该方法可能会有所不同,因为TestNG仅创建测试类的一个实例,无论使用Spring还是什么,其余的模拟字段都是必选的。


旧答案:

我不喜欢在spring的conxtext中使用Mockito模拟。但您是否正在寻找类似的东西:

@After public void reset_mocks() {

Mockito.reset(placeOrderService);

}

以上是 使用Mockito时如何在spring测试中清理模拟 的全部内容, 来源链接: utcz.com/qa/432973.html

回到顶部