如何在单元测试中禁用弹簧自动布线以进行@Configuration/@Bean使用

2022-09-02 01:24:29

我想使用弹簧测试配置内部类()配置组件测试。测试的组件有一些服务,我想模拟测试。这些服务是类(不使用接口),并且其中有弹簧注释()。Mockito可以很容易地嘲笑他们,但是,我发现没有办法禁用弹簧自动布线。@Configuration@Autowired

我如何轻松复制的示例:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SomeTest.Beans.class)
public class SomeTest {

    // configured in component-config.xml, using ThirdPartyService
    @Autowired
    private TestedBean entryPoint;

    @Test
    public void test() {
    }

    @Configuration
    @ImportResource("/spring/component-config.xml")
    static class Beans {
        @Bean
        ThirdPartyService createThirdPartyService() {
            return mock(ThirdPartyService.class);
        }
    }
}

public class ThirdPartyService {
    @Autowired
    Foo bar;
}

public class TestedBean {
    @Autowired
    private ThirdPartyService service;
}

在此示例中,“TestBean”表示要模拟的服务。我不希望“酒吧”在春天被注入! 没有帮助(实际上,这是默认值)。(请从“使用界面!”评论中拯救我 - 模拟服务可以是第三方,我无法做任何事情。@Bean(autowire = NO)

更新

Springockito部分解决了这个问题,只要你不必有其他任何东西要配置(所以你不能在Springockito上使用配置类 - 它不支持它),但只使用模拟。仍然在寻找纯弹簧解决方案,如果有的话...


答案 1

以下是我对您的问题的解决方案:

import static org.mockito.Mockito.mockingDetails;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MockitoSkipAutowireConfiguration {

@Bean MockBeanFactory mockBeanFactory() {
    return new MockBeanFactory();
}

private static class MockBeanFactory extends InstantiationAwareBeanPostProcessorAdapter {
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        return !mockingDetails(bean).isMock();
    }
}

} 

然后只是

@Import(MockitoSkipAutowireConfiguration.class)

在你的测试中,你都准备好了@Configuration


答案 2

我通过为我的Bean创建FactoryBean而不是仅仅嘲笑Bean来解决它。通过这种方式,Spring不要尝试自动连接字段。

工厂豆类帮助类:

public class MockitoFactoryBean<T> implements FactoryBean<T> {
    private final Class<T> clazz;

    public MockitoFactoryBean(Class<T> clazz) {
        this.clazz = clazz;
    }

    @Override public T getObject() throws Exception {
        return mock(clazz);
    }

    @Override public Class<T> getObjectType() {
        return clazz;
    }

    @Override public boolean isSingleton() {
        return true;
    }
}

实际测试上下文部分:

@Configuration
public class TestContext {

    @Bean
    public FactoryBean<MockingService> mockingService() {
        return new MockitoFactoryBean<>(MockingService.class);
    }
}

推荐