Spring JPA Repository findAll 在 JUnit 测试中不返回任何数据

Posted

技术标签:

【中文标题】Spring JPA Repository findAll 在 JUnit 测试中不返回任何数据【英文标题】:Spring JPA Repository findAll returns no data in JUnit test 【发布时间】:2016-06-24 21:20:13 【问题描述】:

我的 jpa 存储库在 spring-boot Web 应用程序中的集成测试存在问题。 服务方法的测试失败,因为访问的存储库没有返回任何结果。但是数据库的事务应该包含数据,因为在日志显示测试事务已经开始之后,SQL 脚本会正确执行。

如果将代码用作Web-service,数据可以按预期访问,所以似乎是测试的事务有问题。

谁能指出我解决这个问题的正确方向?

PS:@Data 来自 https://projectlombok.org/,它创建了一个完整的 bean。

这是我对应的代码:

实体

@Entity
@Data
public class ConcreteEvent 
   @Id
   @GeneratedValue(strategy = GenerationType.AUTO)
   private long id;
   private String caption;
   private String description;
   @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
   private DateTime startDate;
   @Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTime")
   private DateTime endDate;

存储库

public interface ConcreteEventRepository 
    extends PagingAndSortingRepository<ConcreteEvent, Long> 

服务

@Service
public class CalenderEventServiceImpl implements CalendarEventService 

    @Autowired
    private ConcreteEventRepository concreteEventRepository;

    @Override
    public List<ConcreteEvent> getCalendarEventsForDay(DateTime day) 
        List<ConcreteEvent> list = new ArrayList<>();
        Iterable<ConcreteEvent> findAll = concreteEventRepository.findAll();
        findAll.forEach(list::add);
        return list;
    

测试

@ActiveProfiles("test")
@SpringApplicationConfiguration(Application.class)
@WebAppConfiguration
@DirtiesContext
@TestExecutionListeners( DependencyInjectionTestExecutionListener.class,
    DirtiesContextTestExecutionListener.class )
public class CalendarEventServiceTest 
    extends AbstractTransactionalJUnit4SpringContextTests 

    @Autowired
    private CalendarEventService calendarEventService;

    @Before
    public void initialize()
    
        executeSqlScript("classpath:concreteEvents.sql", false);
    

    @Test
    public void testGetCalendarEventsForDay_UseConcreteEvents() 
        List<ConcreteEvent> calendarEventsForDateTime = calendarEventService.getCalendarEventsForDay(new DateTime(2016, 06, 20, 18, 00));

        assertNotNull("No list of events retrieved", calendarEventsForDateTime);
        assertEquals("Not the correct number of events retrieved", 2, calendarEventsForDateTime.size());
    

SQL 脚本

INSERT INTO CONCRETEEVENT (ID, CAPTION, DESCRIPTION, STARTDATE, ENDDATE) values (1, 'TestEvent1', 'Test Description 1', PARSEDATETIME('2016-06-24 18:00', 'yyyy-MM-dd hh:mm'), PARSEDATETIME('2016-06-24 20:00', 'yyyy-MM-dd hh:mm'));

INSERT INTO CONCRETEEVENT (ID, CAPTION, DESCRIPTION, STARTDATE, ENDDATE) values (2, 'TestEvent2', 'Test Description 2', PARSEDATETIME('2016-06-24 18:15', 'yyyy-MM-dd hh:mm'), PARSEDATETIME('2016-06-24 20:15', 'yyyy-MM-dd hh:mm'));

日志

o.s.t.c.transaction.TransactionContext   : Began transaction (1) for test context [DefaultTestContext@6b09bb57 testClass = CalendarEventServiceTest, testInstance = service.CalendarEventServiceTest@556aed22, testMethod = testGetCalendarEventsForDay_UseConcreteEvents@CalendarEventServiceTest, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@6536e911 testClass = CalendarEventServiceTest, locations = '', classes = 'class api.Application', contextInitializerClasses = '[]', activeProfiles = 'test', propertySourceLocations = '', propertySourceProperties = '', resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.SpringApplicationContextLoader', parent = [null]]]; transaction manager [org.springframework.orm.hibernate5.HibernateTransactionManager@3b66ac74]; rollback [true]
o.s.jdbc.datasource.init.ScriptUtils     : Executing SQL script from class path resource [api/calendar/service/concreteEvents.sql]
o.s.jdbc.datasource.init.ScriptUtils     : Executed SQL script from class path resource [api/calendar/service/concreteEvents.sql] in 7 ms.
o.h.h.i.QueryTranslatorFactoryInitiator  : HHH000397: Using ASTQueryTranslatorFactory
o.s.t.c.transaction.TransactionContext   : Rolled back transaction for test context [DefaultTestContext@6b09bb57 testClass = CalendarEventServiceTest, testInstance = api.calendar.service.CalendarEventServiceTest@556aed22, testMethod = testGetCalendarEventsForDay_UseConcreteEvents@CalendarEventServiceTest, testException = java.lang.AssertionError: Not the correct number of events retrieved expected:<2> but was:<0>, mergedContextConfiguration = [WebMergedContextConfiguration@6536e911 testClass = CalendarEventServiceTest, locations = '', classes = 'class api.Application', contextInitializerClasses = '[]', activeProfiles = 'test', propertySourceLocations = '', propertySourceProperties = '', resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.SpringApplicationContextLoader', parent = [null]]].
o.s.w.c.s.GenericWebApplicationContext   : Closing org.springframework.web.context.support.GenericWebApplicationContext@56620197: startup date [Fri Jun 24 22:50:25 CEST 2016]; root of context hierarchy

配置

休眠测试配置:

@Configuration
@Profile("test")
public class HibernateTestConfiguration extends HibernateConfiguration 

    @Bean
    @Override
    public DataSource dataSource() 
        DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setPassword(environment.getRequiredProperty("jdbc.test.password"));
        dataSource.setDriverClassName("org.h2.Driver");
        dataSource.setUrl("jdbc:h2:mem:dataSource;DB_CLOSE_DELAY=-1");
        dataSource.setUsername("sa");
        dataSource.setPassword("");
        return dataSource;
    

    @Override
    protected Properties hibernateProperties() 
        Properties properties = new Properties();
        properties.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
        properties.put("hibernate.show_sql", "true");
        properties.put("hibernate.format_sql", "true");
        properties.put("hibernate.hbm2ddl.auto", "create");
        return properties;
    

休眠配置:

@Configuration
@EnableJpaRepositories("api")
@EnableTransactionManagement
@PropertySource(value =  "classpath:application.properties" )
@Profile("default")
public class HibernateConfiguration 

    private static final String[] PACKAGES_TO_SCAN = new String[]  "api" ;
    @Autowired
    protected Environment environment;

    @Bean
    public LocalSessionFactoryBean sessionFactory() 
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());        
        sessionFactory.setPackagesToScan(PACKAGES_TO_SCAN);
        sessionFactory.setHibernateProperties(hibernateProperties());
        return sessionFactory;
      

    @Bean
    public EntityManagerFactory entityManagerFactory() 

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

        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setJpaVendorAdapter(vendorAdapter);
        factory.setPackagesToScan(PACKAGES_TO_SCAN);
        factory.setDataSource(dataSource());
        factory.afterPropertiesSet();

        return factory.getObject();
    

    @Bean
    public DataSource dataSource() 
        // stripped for brevity
    

    protected Properties hibernateProperties() 
        // stripped for brevity
    

    @Bean
    @Autowired
    public HibernateTransactionManager transactionManager(SessionFactory s) 
       HibernateTransactionManager txManager = new HibernateTransactionManager();
       txManager.setSessionFactory(s);
       return txManager;
    

应用配置:

@Configuration
@EnableAutoConfiguration
@ComponentScan("api")
@EnableWebMvc
public class AppConfiguration 


应用:

@SpringBootApplication
public class Application 
    public static void main(String[] args) 
        SpringApplication.run(Application.class, args);
    

依赖关系

spring-boot-starter-web: 1.3.5 spring-boot-starter-data-jpa: 1.3.5 spring-boot-starter-test: 1.3.5 弹簧测试:4.2.6 spring-orm:4.2.6 h2: 1.4.191

【问题讨论】:

【参考方案1】:

我发现了我的错误。

HibernateConfiguration 类中,我覆盖了事务管理器。这是从教程中摘录的,似乎没有必要。

因此 bean transactionManager 已从类中删除。

还可以删除注释@EnableJpaRepositories("api")@EnableTransactionManagement 和bean entityManagerFactory

【讨论】:

如果这确实是您问题的答案,您可以将您的答案标记为已接受的答案。【参考方案2】:

配置 H2 数据库 打开application.properties文件,添加配置:

spring.h2.console.enabled=true  
spring.h2.console.path=/h2_console  
spring.datasource.url=jdbc:h2:file:~/h2/testdb  
spring.datasource.username=sa  
spring.datasource.password=  
spring.datasource.driverClassName=org.h2.Driver  
spring.jpa.hibernate.ddl-auto = update  
spring.jpa.show-sql=true  

【讨论】:

以上是关于Spring JPA Repository findAll 在 JUnit 测试中不返回任何数据的主要内容,如果未能解决你的问题,请参考以下文章

Spring Data JPA 提供的各种Repository接口作用

spring boot: spring-data-jpa (Repository/CrudRepository) 数据库操作, @Entity实体类持久化

使用 RepositoryItemReader 和 Repository Item writer 的 spring 数据 JPA 的 spring 批处理

Spring Data JPA Repository:如何有条件地获取子实体

删除分离实体spring jpa Repository接口

Spring JPA Repository 生成不正确的 SQL