当前位置: 首页 > 知识库问答 >
问题:

如何构建Spring Boot Atomikos测试配置?

国阳
2023-03-14

如何创建合适的测试环境,使之能够在同一应用程序中使用数据库层测试和RESTendpoint测试?

>

  • 创建一个用于所有测试的测试配置(因为Spring缓存测试上下文)。但这不起作用。我认为这是因为@Controller中的模拟bean中断了重用Spring测试上下文的能力。我在测试中使用持久性映射器组件在一个测试中被模拟,同时在其他测试中使用真实实例。所以我看到每个测试类都运行在它自己的测试上下文中。

    在database@configuration类上使用@lazy正如我所想的那样,这将确保bean只在首次调用时被实例化,并在以后的调用中被重用。但这也行不通。

    在这里,我做了示例项目链接来说明这个问题。存储库包括MySQL数据库转储:https://github.com/pavelmorozov/atomikosconfig

    java.lang.IllegalStateException: Failed to load ApplicationContext
        at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
        at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83)
        at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:189)
        at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:131)
        at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:230)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:228)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:287)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:289)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:247)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
        at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
        at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
        at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
        at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
        at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:539)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:761)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:461)
        at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:207)
    Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'demoController': Unsatisfied dependency expressed through field 'firstMapper'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'firstMapper' defined in file [/home/pm/Documents/workspace-sts-3.9.1.RELEASE/AtomikosConfig/target/classes/com/example/demo/persistence/mapper/first/FirstMapper.class]: Cannot resolve reference to bean 'firstSqlSessionFactory' while setting bean property 'sqlSessionFactory'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'firstSqlSessionFactory' defined in class path resource [com/example/demo/persistence/configuration/FirstDatabaseConfiguration.class]: Unsatisfied dependency expressed through method 'firstSqlSessionFactory' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'firstDataSource' defined in class path resource [com/example/demo/persistence/configuration/FirstDatabaseConfiguration.class]: Invocation of init method failed; nested exception is com.atomikos.jdbc.AtomikosSQLException: Cannot initialize AtomikosDataSourceBean
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588)
        at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693)
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)
        at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:120)
        at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98)
        at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)
        ... 25 more
    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'firstMapper' defined in file [/home/pm/Documents/workspace-sts-3.9.1.RELEASE/AtomikosConfig/target/classes/com/example/demo/persistence/mapper/first/FirstMapper.class]: Cannot resolve reference to bean 'firstSqlSessionFactory' while setting bean property 'sqlSessionFactory'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'firstSqlSessionFactory' defined in class path resource [com/example/demo/persistence/configuration/FirstDatabaseConfiguration.class]: Unsatisfied dependency expressed through method 'firstSqlSessionFactory' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'firstDataSource' defined in class path resource [com/example/demo/persistence/configuration/FirstDatabaseConfiguration.class]: Invocation of init method failed; nested exception is com.atomikos.jdbc.AtomikosSQLException: Cannot initialize AtomikosDataSourceBean
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:359)
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1531)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1276)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:208)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1138)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066)
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585)
        ... 43 more
    Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'firstSqlSessionFactory' defined in class path resource [com/example/demo/persistence/configuration/FirstDatabaseConfiguration.class]: Unsatisfied dependency expressed through method 'firstSqlSessionFactory' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'firstDataSource' defined in class path resource [com/example/demo/persistence/configuration/FirstDatabaseConfiguration.class]: Invocation of init method failed; nested exception is com.atomikos.jdbc.AtomikosSQLException: Cannot initialize AtomikosDataSourceBean
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:749)
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:467)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1173)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1067)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:513)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
        at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:351)
        ... 56 more
    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'firstDataSource' defined in class path resource [com/example/demo/persistence/configuration/FirstDatabaseConfiguration.class]: Invocation of init method failed; nested exception is com.atomikos.jdbc.AtomikosSQLException: Cannot initialize AtomikosDataSourceBean
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1628)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:208)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1138)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066)
        at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:835)
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:741)
        ... 66 more
    Caused by: com.atomikos.jdbc.AtomikosSQLException: Cannot initialize AtomikosDataSourceBean
        at com.atomikos.jdbc.AtomikosSQLException.throwAtomikosSQLException(AtomikosSQLException.java:46)
        at com.atomikos.jdbc.AbstractDataSourceBean.init(AbstractDataSourceBean.java:306)
        at org.springframework.boot.jta.atomikos.AtomikosDataSourceBean.afterPropertiesSet(AtomikosDataSourceBean.java:49)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1687)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1624)
        ... 77 more
    Caused by: javax.naming.NamingException: Another resource already exists with name firstDataSource - pick a different name
        at com.atomikos.util.IntraVmObjectFactory.createReference(IntraVmObjectFactory.java:94)
        at com.atomikos.jdbc.AbstractDataSourceBean.getReference(AbstractDataSourceBean.java:388)
        at com.atomikos.jdbc.AbstractDataSourceBean.init(AbstractDataSourceBean.java:295)
        ... 80 more
    
    @SpringBootApplication
    @EnableAutoConfiguration(
            exclude = {DataSourceAutoConfiguration.class, 
                    DataSourceTransactionManagerAutoConfiguration.class, 
                    MybatisAutoConfiguration.class})
    public class AtomikosConfigApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(AtomikosConfigApplication.class, args);
        }
    }
    

    .

    @Configuration
    @Lazy
    public class FirstDatabaseConfiguration {
    
        @Bean
        public MapperScannerConfigurer firstMapperScannerConfigurer() {
            MapperScannerConfigurer configurer = new MapperScannerConfigurer();
            configurer.setBasePackage("com.example.demo.persistence.mapper.first");
            configurer.setSqlSessionFactoryBeanName("firstSqlSessionFactory");
            return configurer;    
        }
    
        /**
         * This bean uses Atomikos
         * to get transaction atomicity for 
         * few data sources (distributed transaction)
         */
        @Bean
        @ConfigurationProperties(prefix = "spring.jta.atomikos.datasource.first")
        public DataSource firstDataSource() {
            AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
            atomikosDataSourceBean.setPoolSize(10);     
            atomikosDataSourceBean.setMaxLifetime(3600); 
            return atomikosDataSourceBean;
        }
    
        @Bean
        public SqlSessionFactory firstSqlSessionFactory(
                @Qualifier("firstDataSource") DataSource dataSource) throws Exception {
            SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
            sessionFactory.setDataSource(dataSource);
            return sessionFactory.getObject();
        }
    
    }
    

    .

    @Mapper
    public interface FirstMapper {
    
        @Select("SELECT * from first WHERE id = #{id}")
        @Results(value = {
                @Result(property = "id", column = "id"),
                @Result(property = "name", column = "name")
        })
        FirstModel selectById(@Param("id") long id);
    
    }
    

    .

    public class FirstModel {
        private long id;
        private String name;
        public long getId() {
            return id;
        }
        public void setId(long id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
    }
    
    @RestController
    public class DemoController {
    
        @Autowired
        FirstMapper firstMapper;
    
        @Autowired
        SecondMapper secondMapper;
    
        @GetMapping("/demo-controller")
        @Transactional
        public  String getDemoData() {
    
            String firstName = firstMapper.selectById(1).getName();
            String secondName = secondMapper.selectById(1).getName();
    
            String response = "{\"first\":"+firstName+", \"secondName\":"+secondName+"}";
    
            return response; 
        }
    
    }
    
    @RunWith(SpringRunner.class)
    @SpringBootTest
    @EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class,
            DataSourceTransactionManagerAutoConfiguration.class, MybatisAutoConfiguration.class })
    @AutoConfigureMockMvc
    
    public class DemoControllerTest {
    
        @MockBean
        FirstMapper firstMapper;
    
        @MockBean
        SecondMapper secondMapper;
    
        @Autowired
        MockMvc mvc;
    
        @Test
        public void getDemoDataTest() throws Exception {
    
            FirstModel firstModel = new FirstModel();
            firstModel.setId(1);
            firstModel.setName("first name");
            given(firstMapper.selectById(1l)).willReturn(firstModel);
    
            SecondModel secondModel = new SecondModel();
            secondModel.setId(1);
            secondModel.setName("second name");
            given(secondMapper.selectById(1l)).willReturn(secondModel);
    
            mvc.perform(get("/demo-controller").contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
                    .andExpect(jsonPath("$.first", is("first name")));
    
        }
    
    }
    
    @RunWith(SpringRunner.class)
    @SpringBootTest
    @EnableAutoConfiguration(
            exclude = {DataSourceAutoConfiguration.class, 
                    DataSourceTransactionManagerAutoConfiguration.class, 
                    MybatisAutoConfiguration.class
        })
    
    public class FirstMapperTest {
        @Autowired
        FirstMapper firstMapper;
    
        @Test
        public void selectByIdTest() {
            FirstModel first = firstMapper.selectById(1);
            assertEquals("first name", first.getName());
        }
    }
    
  • 共有1个答案

    易弘亮
    2023-03-14

    所以我碰到了这个,在网上也找不到解决的办法。这是我最后要做的:

    我从spring-boot-autoconfigure中复制了很多AtomikosJtaConfiguration,因为自动配置的东西没有被引入到我的测试中。在运行集成测试时,我发现Spring上下文被刷新了很多次,在一些(但不是全部)刷新中,@bean方法被调用来重新创建bean。datasource方法失败了,因为之前的datasource由于某种原因没有被清理,所以我决定使用一个静态变量来保存datasource并每次返回相同的数据源。其余的都起作用了。您应该做的另一件事是将Atomikos设置为在测试期间不编写事务日志,这样测试就可以并行运行,而不会相互踩在一起。

     @Bean
     public DataSource dataSource() throws Exception {
       if (ATOMIKOS_DATA_SOURCE_BEAN == null) {
         if (xaDataSource == null) {
           xaDataSource = createXaDataSource();
         }
         ATOMIKOS_DATA_SOURCE_BEAN = new AtomikosXADataSourceWrapper().wrapDataSource(xaDataSource);
       }
       return ATOMIKOS_DATA_SOURCE_BEAN;
     }
    
     类似资料:
    • 问题内容: 我需要在多种配置上进行构建和测试:linux,osx和solaris。我有标记为“ linux”,“ osx”和“ solaris”的从属节点。在每个配置上,我要(a)建立(b)运行冒烟测试(c)如果冒烟测试通过,然后运行完整测试,也许还要执行更多测试。 我认为多配置作业可能是答案,因此我设置了多配置构建作业,它开始在每个OS上进行并发构建。构建作业将触发下游的烟雾测试构建,进而触发完

    • 问题内容: 我正在尝试使用必须异步加载的配置为我的控制器创建摩卡测试。下面是我的代码。但是,运行mocha测试时,它不会运行任何测试,显示为。该s的甚至从来没有叫。我尝试在describe内执行操作,但是即使运行测试,也从未调用过。有没有一种方法可以在运行任何测试之前一次加载配置? 问题答案: 您应该使用选项运行Mocha ,然后在完成测试套件的构建后再使用。这是从您在问题中显示的代码派生的示例:

    • 我想在与PRODUCTION域相同的范围内构建一个Lotus Notes TEST环境,并从PRODUCTION环境中获得names.nsf的单向副本。您有逐步参考的说明或指南吗?非常感谢。

    • 我观察到m2e在构建期间拾取我想要的配置文件以替换属性。它从哪里获得配置文件?我的父pom有许多配置文件。我的配置文件不存在于settings.xml的activeProfiles部分 我所做的就是右键单击项目并RUn作为maven build。

    • 我有一个构建项目,在其中我实现了Cucumber BDD,并编写了功能文件和测试类。现在,我想要的是在构建过程中

    • 主要内容:第1步:启动JMeter窗口,第2步:添加/删除测试计划元素,第3步:加载并保存测试计划元素。,第4步:配置树元素。,第5步:保存JMeter测试计划。,第6步:运行JMeter测试计划。,第7步:停止JMeter测试计划。,第8步:检查JMeter测试计划执行日志。可以将测试计划可视化为用于运行测试的JMeter脚本。测试计划由测试元素组成,例如线程组,逻辑控制器,样本生成控制器,监听器,定时器,断言和配置元素。 每个测试计划中至少应有一个线程组。 我们可以根据要求添加或删除元素。