java - 让我的 Spring 测试切片扫描单个类而不是整个包

标签 java spring-boot testing

我被要求为现有的 SpringBoot 项目创建集成测试,该项目的组织并不像我希望的那样模块化。例如,有一个包生成与所有服务关联的所有存储库。当我尝试创建 @WebMvcTest 测试切片时,这对我来说成为了一个问题,因为当我使用 @ComponentScan@EnableJpaRepositories@EntityScan 来读取我的目标类,它最终会扫描共享同一包的所有其他不必要的类。

由于更改项目结构实际上并不是我可以自己做出的决定,因此我的问题是是否可以让我的测试扫描选择一个特定的类并忽略同一包中的所有其他类?

感谢您的关注

最佳答案

感谢约瑟夫的回答和这些,我终于能够实现所有必需的过滤:

组件和服务可以配置为产生过滤器,因此我们可以指定目标服务和 Controller ,并同时排除其他所有内容:

 @ComponentScan(
        basePackageClasses = {
                MyTargetService.class,
                MyTargetController.class
        },
        useDefaultFilters = false,
        includeFilters = {
                @ComponentScan.Filter(type = ASSIGNABLE_TYPE, value = MyTargetService.class),
                @ComponentScan.Filter(type = ASSIGNABLE_TYPE, value = MyTargetController.class)

        }
)

存储库。这不太可能适用于存储库,但幸运的是,@EnableJpaRepositories 支持相同类型的过滤器:

  @EnableJpaRepositories(
       basePackageClasses = {
            MyTargetRepository.class
       },
       includeFilters = {
            @ComponentScan.Filter(type = ASSIGNABLE_TYPE, value = MyTargetRepository.class)
       }
  )

实体。这部分比较棘手,因为@EntityScan不支持这些过滤器。尽管实体不引用 Spring bean,但我更喜欢仅加载测试所需的实体。我无法找到支持过滤的实体的任何注释,但我们可以使用 EntityManagerFactory 中的 PersistenceUnitPostProcessor 以编程方式过滤它们。这是我的完整解决方案:

   //add also the filtered @ComponentScan and @EnableJpaRepositories annotations here
   @Configuration
   public class MyConfig {

    //here we specify the packages of our target entities
    private static String[] MODEL_PACKAGES = {
            "com.full.path.to.entity.package1",
            "com.full.path.to.entity.package2"
    };

    //here we specify our target entities
    private static Set<String> TARGET_ENTITIES = new HashSet<>(Arrays.asList(
            "com.full.path.to.entity.package1.MyTargetEntity1",
            "com.full.path.to.entity.package2.MyTargetEntity2"
    ));

    @Bean
    public DataSource getDataSource() {
        EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
        return builder.setType(EmbeddedDatabaseType.H2).build();
    }

    @Bean
    public EntityManagerFactory entityManagerFactory() {

        ReflectionsPersistenceUnitPostProcessor reflectionsPersistenceUnitPostProcessor = new ReflectionsPersistenceUnitPostProcessor();

        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setGenerateDdl(true);
        vendorAdapter.setShowSql(true);

        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setJpaVendorAdapter(vendorAdapter);
        factory.setPackagesToScan(MODEL_PACKAGES);
        factory.setDataSource(getDataSource());
        factory.setPersistenceUnitPostProcessors(reflectionsPersistenceUnitPostProcessor);
        factory.afterPropertiesSet();

        return factory.getObject();
    }


    @Bean
    public PlatformTransactionManager transactionManager() {
        JpaTransactionManager txManager = new JpaTransactionManager();
        txManager.setEntityManagerFactory(entityManagerFactory());
        return txManager;
    }

    public class ReflectionsPersistenceUnitPostProcessor implements PersistenceUnitPostProcessor {

        @Override
        public void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo pui) {

            Reflections r = new Reflections("", new TypeAnnotationsScanner());
            Set<Class<?>> entityClasses = r.getTypesAnnotatedWith(Entity.class, true);
            Set<Class<?>> mappedSuperClasses = r.getTypesAnnotatedWith(MappedSuperclass.class, true);

            pui.getManagedClassNames().clear(); //here we remove all entities

            //here we add only the ones we are targeting
            for (Class<?> clzz : mappedSuperClasses) {
                if (TARGET_ENTITIES.contains(clzz.getName())) {
                    pui.addManagedClassName(clzz.getName());
                }
            }
            for (Class<?> clzz : entityClasses) {
                if (TARGET_ENTITIES.contains(clzz.getName())) {
                    pui.addManagedClassName(clzz.getName());
                }
            }

        }

    }


}

关于java - 让我的 Spring 测试切片扫描单个类而不是整个包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60260228/

相关文章:

java - 正则表达式java从txt文件中查找字符串

java - 天气应用程序 (JSON) 数据未显示在 TextView 中

java - "Invalid content was found starting with element ' http :basicAuthSupplier '" while building Apache CXF project

testing - 单声道命令行单元测试

unit-testing - 网站测试员的文件?

java - 区 block a4j :support call when the input value is empty

java - Springboot解密JNDI tomcat密码

java - 使用 ldap 时出现 AcceptSecurityContext 错误

java - 在 Spring 上下文之前动态创建 schema.sql

xslt - 引用 xsl 中的属性值 :param xsl:if test condition