Spring4 / JUnit4 嵌入式数据库未加载,可能是项目配置错误

Posted

技术标签:

【中文标题】Spring4 / JUnit4 嵌入式数据库未加载,可能是项目配置错误【英文标题】:Spring4 / JUnit4 embedded database not loading, possibly misconfigured project 【发布时间】:2016-02-09 04:47:24 【问题描述】:

以为我拥有一切,但不是真的,所以我寻求帮助。

我有一个小型 Spring 4 (WebMvc) 项目,它在 mysql 中的一个表(在我的代码中为 Location 类)上执行 CRUD 活动。我在 Tomcat 8 上的 Spring 4 中运行良好,没有单元测试。

现在我添加了单元测试,但无法正确配置 JUnit。我想我正确地设置了一个嵌入式 HSQL 数据库,但是我的 JUnit 测试说没有记录。我可以找人帮我理顺吗?

该程序实际上并没有命名为“MyProgram”,路径也不是“mypackagepath”,而是将内容编辑为缩短内容。首先,这里是工作程序的配置部分:

@Configuration
@ComponentScan(basePackages = "mypackagepath")
@EnableWebMvc
public class MyProgramConfiguration extends WebMvcConfigurerAdapter  ... 

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry)  ... 

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry)  ... 


@Configuration
@EnableTransactionManagement
@ComponentScan( "mypackagepath.configuration" )
@PropertySource(value =  "classpath:application.properties" )
@EnableJpaRepositories(basePackages =  "mypackagepath.dao" )
public class JpaConfiguration 

    @Autowired
    private Environment environment;

    @Bean(name="entitymanagername")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory()  ... 

    @Bean
    public DataSource dataSource()  ... 

    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory emf)  ... 


public class SpringMvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer 

    @Override
    protected Class<?>[] getRootConfigClasses()  ... 

    @Override
    protected Class<?>[] getServletConfigClasses()  ... 

    @Override
    protected String[] getServletMappings()  ... 


测试代码中的类似配置有:

@Configuration
@EnableTransactionManagement
@ComponentScan(basePackages =  "mypackagepath.configuration" , 
        excludeFilters = @ComponentScan.Filter(value = JpaConfiguration.class, type = FilterType.ASSIGNABLE_TYPE ) )
public class TestJpaConfiguration 

    @Value("classpath:createLocationTableForTest.sql")
    private String createLocationTableScript;

    @Value("classpath:fillLocationTableForTest.sql")
    private String fillLocationTableScript;

    @Autowired
    private Environment environment;

    @Bean(name="myentitymanagername")
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() 
    LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
    em.setDataSource(dataSource());
    em.setPersistenceUnitName("myentitymanagername");
    em.setPackagesToScan(new String[]  "mypackagepath.model" );

    JpaVendorAdapter va = new HibernateJpaVendorAdapter();
    em.setJpaVendorAdapter(va);
    em.setJpaProperties(additionalProperties());
    em.afterPropertiesSet();

    return em;
    

    /*
     * The individual table filling scripts are defined
     * and run in the test classes. 
     */
    @Bean(destroyMethod = "shutdown")    
    public DataSource dataSource() 
        EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
        EmbeddedDatabase db = builder
            .setType(EmbeddedDatabaseType.HSQL)
            .addScript(createLocationTableScript)
            .addScript(fillLocationTableScript)
            .build();

        return db;
    

    @Bean
    public PlatformTransactionManager transactionManager() 
    JpaTransactionManager tm = new JpaTransactionManager();
    tm.setEntityManagerFactory( this.entityManagerFactoryBean().getObject() );

    return tm;
    

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation() 
    return new PersistenceExceptionTranslationPostProcessor();
    

    Properties additionalProperties() 
    Properties properties = new Properties();
    properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
    properties.put("hibernate.hbm2ddl.auto", environment.getRequiredProperty("hibernate.hbm2ddl.auto"));
    properties.put("jadira.usertype.autoRegisterUserTypes", environment.getRequiredProperty("jadira.usertype.autoRegisterUserTypes"));

    return properties;        
   


我在 main/resources 和 test/resources 目录中有一个 application.properties 文件。当然,“测试”具有 HSQL 属性。

我认为记录没有加载(来自 fillLocationTableForTest.sql 文件),因为我的 MySQL 版本的测试表中有很多记录(如果测试配置被忽略)并且 JUnit 测试失败:

@Test
public final void testSummaryCountTotal() 
    Summary summary = summaryDao.getSummary();
    assertThat(summary.getCountTotal(), equalTo(12L));

这会返回 java.lang.AssertionError: Expected but was ...

对于它的价值,在我的控制台中我的 JUnit 运行给了我:

[main] INFO org.springframework.test.context.web.WebTestContextBootstrapper - Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]
[main] INFO org.springframework.test.context.web.WebTestContextBootstrapper - Using TestExecutionListeners: [org.springframework.test.context.web.ServletTestExecutionListener@193948d, org.springframework.test.context.support.DependencyInjectionTestExecutionListener@1604f19, org.springframework.test.context.support.DirtiesContextTestExecutionListener@23a2f9, org.springframework.test.context.transaction.TransactionalTestExecutionListener@c0edeb, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener@17e2f02]
[main] INFO org.springframework.web.context.support.GenericWebApplicationContext - Refreshing org.springframework.web.context.support.GenericWebApplicationContext@dd8682: startup date [Tue Feb 09 03:51:34 CST 2016]; root of context hierarchy
[main] INFO org.springframework.beans.factory.support.DefaultListableBeanFactory - Overriding bean definition for bean 'dataSource': replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=jpaConfiguration; factoryMethodName=dataSource; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [mypackagepath/configuration/JpaConfiguration.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=testJpaConfiguration; factoryMethodName=dataSource; initMethodName=null; destroyMethodName=(inferred); defined in mypackagepath.configuration.TestJpaConfiguration]
[main] INFO org.springframework.beans.factory.support.DefaultListableBeanFactory - Overriding bean definition for bean 'exceptionTranslation': replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=jpaConfiguration; factoryMethodName=exceptionTranslation; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [mypackagepath/configuration/JpaConfiguration.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=testJpaConfiguration; factoryMethodName=exceptionTranslation; initMethodName=null; destroyMethodName=(inferred); defined in mypackagepath.configuration.TestJpaConfiguration]
[main] INFO org.springframework.beans.factory.support.DefaultListableBeanFactory - Overriding bean definition for bean 'myentitymanagername': replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=jpaConfiguration; factoryMethodName=entityManagerFactory; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [mypackagepath/configuration/JpaConfiguration.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=testJpaConfiguration; factoryMethodName=entityManagerFactoryBean; initMethodName=null; destroyMethodName=(inferred); defined in mypackagepath.configuration.TestJpaConfiguration]
[main] INFO org.springframework.beans.factory.support.DefaultListableBeanFactory - Overriding bean definition for bean 'transactionManager': replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=jpaConfiguration; factoryMethodName=transactionManager; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [mypackagepath/configuration/JpaConfiguration.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=testJpaConfiguration; factoryMethodName=transactionManager; initMethodName=null; destroyMethodName=(inferred); defined in mypackagepath.configuration.TestJpaConfiguration]

[main] INFO org.springframework.context.support.PostProcessorRegistrationDelegate$BeanPostProcessorChecker - Bean 'testJpaConfiguration' of type [class mypackagepath.configuration.TestJpaConfiguration$$EnhancerBySpringCGLIB$$d9ae76ba] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
[main] INFO org.springframework.jdbc.datasource.DriverManagerDataSource - Loaded JDBC driver: org.hsqldb.jdbcDriver
[main] INFO org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean - Building JPA container EntityManagerFactory for persistence unit 'myentitymanagername'
INFO : org.hibernate.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [
    name: myentitymanagername
    ...]
INFO : org.hibernate.Version - HHH000412: Hibernate Core 4.3.6.Final
INFO : org.hibernate.cfg.Environment - HHH000206: hibernate.properties not found
INFO : org.hibernate.cfg.Environment - HHH000021: Bytecode provider name : javassist
INFO : org.hibernate.annotations.common.Version - HCANN000001: Hibernate Commons Annotations 4.0.5.Final
INFO : org.hibernate.dialect.Dialect - HHH000400: Using dialect: org.hibernate.dialect.HSQLDialect
INFO : org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory - HHH000397: Using ASTQueryTranslatorFactory
INFO : org.hibernate.validator.internal.util.Version - HV000001: Hibernate Validator 5.1.3.Final
INFO : org.hibernate.type.BasicTypeRegistry - HHH000270: Type registration [java.util.Currency] overrides previous : org.hibernate.type.CurrencyType@1ffa30b
INFO : org.hibernate.tool.hbm2ddl.SchemaExport - HHH000227: Running hbm2ddl schema export
INFO : org.hibernate.tool.hbm2ddl.SchemaExport - HHH000230: Schema export complete
[main] INFO org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean - Building JPA container EntityManagerFactory for persistence unit 'myentitymanagername'
INFO : org.hibernate.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [
    name: myentitymanagername
    ...]

INFO : org.hibernate.dialect.Dialect - HHH000400: Using dialect: org.hibernate.dialect.HSQLDialect
INFO : org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory - HHH000397: Using ASTQueryTranslatorFactory
INFO : org.hibernate.type.BasicTypeRegistry - HHH000270: Type registration [java.util.Currency] overrides previous : org.hibernate.type.CurrencyType@1ffa30b
INFO : org.hibernate.tool.hbm2ddl.SchemaExport - HHH000227: Running hbm2ddl schema export
INFO : org.hibernate.tool.hbm2ddl.SchemaExport - HHH000230: Schema export complete
WARN : org.hibernate.jpa.internal.EntityManagerFactoryRegistry - HHH000436: Entity manager factory name (myentitymanagername) is already registered.  If entity manager will be clustered or passivated, specify a unique value for property 'hibernate.ejb.entitymanager_factory_name'
[main] INFO org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "[//location/id],methods=[GET],params=[],headers=[],consumes=[],produces=[application/json],custom=[]" onto public org.springframework.http.ResponseEntity<mypackagepath.model.Location> mypackagepath.controller.LocationController.getEdit(java.lang.Long)
[main] INFO org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "[//location/id],methods=[PUT],params=[],headers=[],consumes=[application/json],produces=[application/json],custom=[]" onto public org.springframework.http.ResponseEntity<mypackagepath.model.Location> mypackagepath.controller.LocationController.putEdit(mypackagepath.model.Location,java.lang.Long)
[main] INFO org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "[//next/id/type/type],methods=[GET],params=[],headers=[],consumes=[],produces=[application/json],custom=[]" onto public org.springframework.http.ResponseEntity<mypackagepath.model.Location> mypackagepath.controller.LocationController.getNextEdit(java.lang.Long,java.lang.String)
[main] INFO org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "[/main],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]" onto public java.lang.String mypackagepath.controller.MainController.getMainPage()
[main] INFO org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "[//address/address/key],methods=[GET],params=[],headers=[],consumes=[],produces=[application/json],custom=[]" onto public org.springframework.http.ResponseEntity<java.lang.String> mypackagepath.controller.ProxyAccessController.getAddress(java.lang.String,java.lang.String)
[main] INFO org.springframework.web.servlet.handler.SimpleUrlHandlerMapping - Mapped URL path [/static/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
[main] INFO org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter - Looking for @ControllerAdvice: org.springframework.web.context.support.GenericWebApplicationContext@dd8682: startup date [Tue Feb 09 03:51:34 CST 2016]; root of context hierarchy
[Thread-1] INFO org.springframework.web.context.support.GenericWebApplicationContext - Closing org.springframework.web.context.support.GenericWebApplicationContext@dd8682: startup date [Tue Feb 09 03:51:34 CST 2016]; root of context hierarchy
[Thread-1] INFO org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean - Closing JPA EntityManagerFactory for persistence unit 'myentitymanagername'

我的请求:有人可以帮我整理一个适用于 Tomcat 和 JUnit 的 Spring / JUnit 配置吗?

谢谢, 杰罗姆。

【问题讨论】:

【参考方案1】:

我有解决问题的方法,但可能不是最好的。我仍在寻找更好的解决方案。

在我的 TestJpaConfiguration.dataSource() 中,我删除了 addScript() 调用:

@Bean(destroyMethod = "shutdown")    
public DataSource dataSource() 
    EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
    EmbeddedDatabase db = builder
        .setType(EmbeddedDatabaseType.HSQL)
        //.addScript(createLocationTableScript)
        //.addScript(fillLocationTableScript)
        .build();

    return db;

在每个测试 Java 文件中,我在每个 setUp() / tearDown() 对中设置了一个嵌入式数据库:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes =  TestJpaConfiguration.class , loader = AnnotationConfigWebContextLoader.class)
@WebAppConfiguration
public class SummaryDaoTest 

    @Value("classpath:createLocationTableForTest.sql")
    private String createLocationTableScript;

    @Value("classpath:fillLocationTableForTest.sql")
    private String fillLocationTableScript;

    @Autowired
    private EmbeddedDatabase db;

    @Autowired
    private SummaryDao summaryDao;

    @BeforeClass
    public static void setUpBeforeClass() throws Exception 
    

    @AfterClass
    public static void tearDownAfterClass() throws Exception 
    

    @Before
    public void setUp() throws Exception 
    db = new EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.HSQL)
            .addScript(createLocationTableScript)
            .addScript(fillLocationTableScript)
            .build();
    

    @After
    public void tearDown() throws Exception 
        db.shutdown();
    

    // After this come the tests...


这对我有用——代码通过了它的 JUnit 测试,可以部署到 Tomcat 并且在那里工作正常。

我能否在每次测试中“不重复自己”得到改进?

谢谢, 杰罗姆。

【讨论】:

以上是关于Spring4 / JUnit4 嵌入式数据库未加载,可能是项目配置错误的主要内容,如果未能解决你的问题,请参考以下文章

Maven3.0+Spring MVC4+Spring 4+Mybatis3+junit4

CSV::MalformedCSVError: 未加引号的字段在 Ruby 中不允许 \r 或 \n

mysqlbinlog结合sed命令恢复update时未加where条件之前的数据

C#-WebForm-★★★LinQ-数据的条件组合查询并进行分页展示(未加各种限定)★★★

Junit4

21000多台未加保护的Elasticsearch服务器上发现了超过43 TB的数据