Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/eclipse/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring mvc 使用Mockito时如何清理spring测试中的mock_Spring Mvc_Mockito_Spring Test - Fatal编程技术网

Spring mvc 使用Mockito时如何清理spring测试中的mock

Spring mvc 使用Mockito时如何清理spring测试中的mock,spring-mvc,mockito,spring-test,Spring Mvc,Mockito,Spring Test,我对莫基托很陌生,在清理方面遇到了一些麻烦 我曾经使用JMock2进行单元测试。据我所知,JMock2将期望和其他模拟信息保存在一个上下文中,该上下文将为每个测试方法重建。因此,每种试验方法都不会受到其他方法的干扰 在使用JMock2时,我对spring测试采用了相同的策略,我发现我在中使用的策略存在一个潜在问题:为每个测试方法重建应用程序上下文,因此会减慢整个测试过程 我注意到许多文章推荐在spring测试中使用Mockito,我想尝试一下。在我在一个测试用例中编写两个测试方法之前,它工作得很

我对莫基托很陌生,在清理方面遇到了一些麻烦

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

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

我注意到许多文章推荐在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(...);

}

您不应该注入
placeOrderService
对象,而应该在每次测试之前让Mockito将其初始化为
@Mock
,方法如下:

@Mock private PlaceOrderService placeOrderService;

@Before
public void setup() {
    MockitoAnnotations.initMocks(this);
}
正如Javadoc中推荐的:

您甚至可以将
@Before
方法放在一个超类中,只需为使用
@Mock
对象的每个测试用例类扩展它

  • 关于在测试方法之后进行重置

    我认为重置模拟最好在测试方法之后进行,因为这意味着测试期间确实发生了一些需要清理的事情

    如果重置是在测试方法之前完成的,我会觉得不确定,在测试之前发生了什么应该重置的事情?非模拟对象呢?这有什么原因吗?如果代码中没有提到它有什么原因(例如方法名)?等等

  • 不喜欢基于Spring的测试

  • 背景

    使用Spring就像放弃对类的单元测试;使用Spring,您对测试的控制就更少了:隔离、实例化、生命周期,仅举几个单元测试中的looked属性。然而,在许多情况下,Spring提供的库和框架并不是那么“透明”,为了测试,您可以更好地测试整个东西的实际行为,比如SpringMVC、SpringBatch等等

    编写这些测试要麻烦得多,因为在许多情况下,开发人员需要编写集成测试来认真测试生产代码的行为。由于许多开发人员不知道您的代码如何在Spring中生存的每一个细节,所以尝试使用单元测试来测试一个类可能会带来很多惊喜

    但问题还在继续,测试应该快速且小,以便向开发人员提供快速反馈(IDE插件,例如,非常适合这样做),但使用Spring的测试天生就更慢,并且更消耗内存。这往往会减少它们的运行频率,甚至完全避免在本地工作站上运行它们……以便稍后在CI服务器上发现它们出现故障

  • Mockito和Spring的生命周期

    因此,当为一个子系统编制一个集成测试时,您最终会遇到许多对象,显然还有可能被模仿的合作者。生命周期由Spring Runner控制,但Mockito Mock不是。因此,您必须自己管理模拟的生命周期

    关于生命周期,在使用Spring批处理的项目中,我们遇到了一些关于非模拟的残余影响的问题,因此我们有两个选择,每个测试类只做一个测试方法,或者使用技巧:
    @DirtiesContext(classMode=classMode.AFTER\u每个测试方法)
    。这会导致测试速度变慢,内存消耗增加,但这是我们最好的选择。使用此技巧,您不必重置Mockito mock

  • 黑暗中可能出现的光线

    我对这个项目不太了解,但我可以给你一些关于生命周期的甜言蜜语。这似乎更好:它似乎让Spring管理Spring容器中bean的生命周期,并让测试控制mock的使用方式。我仍然没有使用此工具的经验,因此可能会有惊喜

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

    另一方面,当JUnit为每个测试方法实例化测试类时,在JUnit上下文中看到这个问题是很有趣的。如果测试基于TestNG,那么方法可能会有点不同,因为TestNG只创建测试类的一个实例,不管使用Spring如何,静态模拟字段都是必需的


    旧答案:

    我不太喜欢在spring conxtext中使用Mockito Mock。但是,您是否可能正在寻找类似于:

    @After public void reset_mocks() {
        Mockito.reset(placeOrderService);
    }
    

    基于Spring的测试很难做到快速和独立(如@Brice)。下面是一个用于重置所有模拟的litle实用程序方法(您必须在每个
    @Before
    方法中手动调用它):

    正如您看到的,所有bean都有一个迭代,检查bean是否为mock,并重置mock。我特别关注call
    AopUtils.isAopProxy
    ((建议)bean).getTargetSource().getTarget()
    。如果您的bean包含一个
    @Transactional
    注释,那么这个bean的模拟总是由spring包装到代理对象中,以便重置或验证
    import org.mockito.Mockito;
    import org.springframework.aop.framework.Advised;
    import org.springframework.aop.support.AopUtils;
    import org.springframework.context.ApplicationContext;
    
    
    public class MyTest {
        public void resetAll(ApplicationContext applicationContext) throws Exception {
            for (String name : applicationContext.getBeanDefinitionNames()) {
                Object bean = applicationContext.getBean(name);
                if (AopUtils.isAopProxy(bean) && bean instanceof Advised) {
                    bean = ((Advised)bean).getTargetSource().getTarget();
                }
                if (Mockito.mockingDetails(bean).isMock()) {
                    Mockito.reset(bean);
                }
            }
        }
    }
    
    @MockBean
    private PlaceOrderService placeOrderService;
    
    @SpringBootTest
    public class MyServiceTest {
    
        @MockInBean(MyService.class)
        private ServiceToMock serviceToMock;
    
        @Autowired
        private MyService myService;
    
        @Test
        public void test() {
            Mockito.when(serviceToMock.returnSomething()).thenReturn(new Object());
            myService.doSomething();
        }
    }
    
    public static void resetMocks(ApplicationContext context) {
        for ( String name : context.getBeanDefinitionNames() ) {
            Object bean = context.getBean( name );
            if (new MockUtil().isMock( bean )) {
                Mockito.reset( bean );
            }
        }
    }