Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/13.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
Java 如何在SpringJUnit4ClassRunner中模拟缺少的bean定义?_Java_Spring_Junit_Spring Test_Spring 4 - Fatal编程技术网

Java 如何在SpringJUnit4ClassRunner中模拟缺少的bean定义?

Java 如何在SpringJUnit4ClassRunner中模拟缺少的bean定义?,java,spring,junit,spring-test,spring-4,Java,Spring,Junit,Spring Test,Spring 4,我有一个Spring4JUnit测试,它应该只验证我的应用程序的一个特定部分 @WebAppConfiguration @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:context-test.xml") @ActiveProfiles("test") public class FooControllerIntegrationTest { ... } 所以我不想配置和实例化所有那些实际上

我有一个Spring4JUnit测试,它应该只验证我的应用程序的一个特定部分

@WebAppConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:context-test.xml")
@ActiveProfiles("test")
public class FooControllerIntegrationTest {
     ...
}
所以我不想配置和实例化所有那些实际上不在我的测试范围内的bean。例如,我不想配置在另一个控制器中使用的bean,我不打算在这里进行测试

但是,因为我不想缩小组件扫描路径,所以我得到了“No qualification bean of type”异常:

原因: org.springframework.beans.factory.noSuchBean定义异常:否 类型为[…]的限定bean


如果我确定这些遗漏的定义没有包含在我正在测试的功能中,那么有没有办法忽略这些遗漏的定义?

如果您不缩小组件扫描范围,那么通常您将拥有所有可用于测试的bean,除了一些有条件可用的特定bean(例如,spring batch定义的bean)

在这种情况下,对我有效的一个选项是将此类依赖项和组件标记为
@Lazy
。这将确保它们仅在需要时加载。注意(取决于场景),您可能必须将
@Autowired
依赖项和
@Component
标记为
@Lazy

如果我确信这些遗漏的定义没有涉及到我正在测试的功能中,有没有办法忽略它们

不,没有用于此目的的自动或内置机制

如果您指示Spring加载对其他bean具有强制依赖关系的bean,那么这些bean必须存在

出于测试目的,限制bean活动范围的最佳实践包括配置的模块化(例如,允许您有选择地选择加载应用程序的哪些层的水平切片)和bean定义配置文件的使用

如果您使用的是Spring Boot,那么您还可以在Spring Boot测试中使用“测试片”或
@MockBean
/
@SpyBean

但是,您应该记住,加载您在给定集成测试中未使用的bean通常不是一件坏事,因为您(希望如此)测试测试套件中其他测试类中实际需要这些bean的其他组件时,
ApplicationContext
将只加载一次,并在不同的集成测试类中缓存

问候,


Sam(SpringTestContext框架的作者)

我找到了一种自动模拟缺失bean定义的方法

核心理念是创建自己的
BeanFactory

public class AutoMockBeanFactory extends DefaultListableBeanFactory {

    @Override
    protected Map<String, Object> findAutowireCandidates(final String beanName, final Class<?> requiredType, final DependencyDescriptor descriptor) {
        String mockBeanName = Introspector.decapitalize(requiredType.getSimpleName()) + "Mock";
        Map<String, Object> autowireCandidates = new HashMap<>();
        try {
            autowireCandidates = super.findAutowireCandidates(beanName, requiredType, descriptor);
        } catch (UnsatisfiedDependencyException e) {
            if (e.getCause() != null && e.getCause().getCause() instanceof NoSuchBeanDefinitionException) {
                mockBeanName = ((NoSuchBeanDefinitionException) e.getCause().getCause()).getBeanName();
            } 
            this.registerBeanDefinition(mockBeanName, BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition());
        }
        if (autowireCandidates.isEmpty()) {
            final Object mock = mock(requiredType);
            autowireCandidates.put(mockBeanName, mock);
            this.addSingleton(mockBeanName, mock);
        }
        return autowireCandidates;
    }
}

与发布的OP一样,以下是用于注入任何模拟缺失bean的注释上下文:

context = new CustomAnnotationConfigApplicationContext(SpringDataJpaConfig.class);

public class CustomAnnotationConfigApplicationContext extends AnnotationConfigApplicationContext {

    public CustomAnnotationConfigApplicationContext() {
        super(new AutoMockBeanFactory());
    }

    public CustomAnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
        this();
        this.register(annotatedClasses);
        this.refresh();
    }
}


public class AutoMockBeanFactory extends DefaultListableBeanFactory {

    @Override
    protected Map<String, Object> findAutowireCandidates(final String beanName, final Class<?> requiredType, final DependencyDescriptor descriptor) {
        String mockBeanName = Introspector.decapitalize(requiredType.getSimpleName());
        Map<String, Object> autowireCandidates = new HashMap<>();
        try {
            autowireCandidates = super.findAutowireCandidates(beanName, requiredType, descriptor);
        } catch (UnsatisfiedDependencyException e) {
            if (e.getCause() != null && e.getCause().getCause() instanceof NoSuchBeanDefinitionException) {
                mockBeanName = ((NoSuchBeanDefinitionException) e.getCause().getCause()).getBeanName();
            }
            this.registerBeanDefinition(mockBeanName, BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition());
        }
        if (autowireCandidates.isEmpty()) {
            System.out.println("Mocking bean: " + mockBeanName);
            final Object mock = Mockito.mock(requiredType);
            autowireCandidates.put(mockBeanName, mock);
            this.addSingleton(mockBeanName, mock);
        }
        return autowireCandidates;
    }
}
context=新的CustomAnnotationConfigApplicationContext(SpringDataJpaConfig.class);
公共类CustomAnnotationConfigApplicationContext扩展了AnnotationConfigApplicationContext{
公共CustomAnnotationConfigApplicationContext(){
super(新的AutoMockBeanFactory());
}
公共CustomAnnotationConfigApplicationContext(类…AnnotatedClass){
这个();
这个。注册(注释类);
这个。刷新();
}
}
公共类AutoMockBeanFactory扩展了DefaultListableBeanFactory{
@凌驾
受保护映射FinDautoWirePredidates(最终字符串beanName、最终类requiredType、最终依赖描述符){
字符串mockBeanName=Introspector.decapitalize(requiredType.getSimpleName());
Map Autowire候选者=新HashMap();
试一试{
autowireCandidates=super.findAutowireCandidates(beanName、requiredType、descriptor);
}捕获(未满足的支出异常e){
如果(e.getCause()!=null&&e.getCause().getCause()实例为NoSuchBeanDefinitionException){
mockBeanName=((NoSuchBeanDefinitionException)e.getCause().getCause()).getBeanName();
}
这个.registerBeanDefinition(mockBeanName、BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition());
}
if(autowire.isEmpty()){
System.out.println(“mockingbean:+mockBeanName”);
最终对象mock=Mockito.mock(requiredType);
autowire.put(mockBeanName,mock);
this.addSingleton(mockBeanName,mock);
}
返回候选人;
}
}

但我不想在生产代码中将我的Bean标记为懒惰。这将在应用程序加载时中断预检查。当然……不过,如果您确实对使用懒惰部分的组件进行了测试,则该风险已被涵盖……无论如何,感谢您的回答。但我非常肯定有一些优雅的方法。例如,一些自定义bean loader,它可以用Mockito自动模拟缺失的依赖项。当然,没问题。我感谢你的回答!非常感谢。但我仍在考虑编写自己的测试工具,自动模拟缺失的依赖项。我至少找到了一个可行的解决方案。请检查我的自我回答:。我真的对你的意见感兴趣。这是一个非常有趣的自定义解决方案。我还没有对实现进行彻底的分析;但是,如果您只想模拟通过自动连线注入的缺少的bean(如果它确实适合您),那么无论如何……使用它!你愿意给出一个关于如何使用它的例子吗?我正试图在@DataJpaTest和@extendedwith(SpringExtension.class)@crystake的测试环境中使用它,这本身就是一个完整的例子,哪种类型(JPA)或模式(*Repo)您想要模拟的bean的数量由您决定。这在某些项目中的集成测试中非常有用,因为有些bean无法创建或不需要。
context = new CustomAnnotationConfigApplicationContext(SpringDataJpaConfig.class);

public class CustomAnnotationConfigApplicationContext extends AnnotationConfigApplicationContext {

    public CustomAnnotationConfigApplicationContext() {
        super(new AutoMockBeanFactory());
    }

    public CustomAnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
        this();
        this.register(annotatedClasses);
        this.refresh();
    }
}


public class AutoMockBeanFactory extends DefaultListableBeanFactory {

    @Override
    protected Map<String, Object> findAutowireCandidates(final String beanName, final Class<?> requiredType, final DependencyDescriptor descriptor) {
        String mockBeanName = Introspector.decapitalize(requiredType.getSimpleName());
        Map<String, Object> autowireCandidates = new HashMap<>();
        try {
            autowireCandidates = super.findAutowireCandidates(beanName, requiredType, descriptor);
        } catch (UnsatisfiedDependencyException e) {
            if (e.getCause() != null && e.getCause().getCause() instanceof NoSuchBeanDefinitionException) {
                mockBeanName = ((NoSuchBeanDefinitionException) e.getCause().getCause()).getBeanName();
            }
            this.registerBeanDefinition(mockBeanName, BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition());
        }
        if (autowireCandidates.isEmpty()) {
            System.out.println("Mocking bean: " + mockBeanName);
            final Object mock = Mockito.mock(requiredType);
            autowireCandidates.put(mockBeanName, mock);
            this.addSingleton(mockBeanName, mock);
        }
        return autowireCandidates;
    }
}