1. 概述

当测试依赖持久层(如JPA)的Spring应用时,我们通常希望为测试配置一个更轻量、更快的数据库,而非生产环境使用的数据库。这能显著提升测试执行效率。

在Spring中配置数据源需要定义一个DataSource类型的bean。我们可以手动创建,或在Spring Boot中通过标准属性文件自动配置。

本文将介绍在Spring中为测试配置独立数据源的几种实用方法

2. Maven依赖

我们将创建一个使用Spring JPA的Spring Boot应用,需要添加以下依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency> 
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>

最新版本可在Maven Central下载:

下面我们探讨几种测试数据源配置方案:

3. 在Spring Boot中使用标准属性文件

Spring Boot默认加载src/main/resources下的application.properties文件。若要为测试使用不同配置,只需在src/test/resources创建同名文件覆盖即可。

测试用的application.properties应包含数据源配置属性(前缀为spring.datasource)。例如配置H2内存数据库:

spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=sa

Spring Boot会自动根据这些属性创建DataSource bean。

定义一个简单的JPA实体和仓库:

@Entity
public class GenericEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String value;

    //标准构造器、getter/setter
}
public interface GenericEntityRepository
  extends JpaRepository<GenericEntity, Long> { }

编写仓库测试类(需添加@SpringBootTest注解):

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class SpringBootJPAIntegrationTest {
 
    @Autowired
    private GenericEntityRepository genericEntityRepository;

    @Test
    public void givenGenericEntityRepository_whenSaveAndRetreiveEntity_thenOK() {
        GenericEntity genericEntity = genericEntityRepository
          .save(new GenericEntity("test"));
        GenericEntity foundEntity = genericEntityRepository
          .findOne(genericEntity.getId());
 
        assertNotNull(foundEntity);
        assertEquals(genericEntity.getValue(), foundEntity.getValue());
    }
}

4. 使用自定义属性文件

若不想使用标准属性文件或未使用Spring Boot,可创建自定义.properties文件,然后在@Configuration类中读取并创建数据源。

将自定义文件(如persistence-generic-entity.properties)放在:

  • src/main/resources(生产环境)
  • src/test/resources(测试环境)

测试环境配置示例(H2内存数据库):

jdbc.driverClassName=org.h2.Driver
jdbc.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
jdbc.username=sa
jdbc.password=sa

在配置类中加载该文件并创建数据源:

@Configuration
@EnableJpaRepositories(basePackages = "org.baeldung.repository")
@PropertySource("persistence-generic-entity.properties")
@EnableTransactionManagement
public class H2JpaConfig {
    // 完整配置参考:[内存数据库自包含测试](/spring-jpa-test-in-memory-database)的JPA配置章节
}

编写测试类(需加载自定义配置类):

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {Application.class, H2JpaConfig.class})
public class SpringBootH2IntegrationTest {
    // 测试代码同上
}

5. 使用Spring Profiles

通过Spring Profiles定义仅在test profile下生效的数据源bean:

@Configuration
@EnableJpaRepositories(basePackages = {
  "org.baeldung.repository",
  "org.baeldung.boot.repository"
})
@EnableTransactionManagement
public class H2TestProfileJPAConfig {

    @Bean
    @Profile("test")
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("org.h2.Driver");
        dataSource.setUrl("jdbc:h2:mem:db;DB_CLOSE_DELAY=-1");
        dataSource.setUsername("sa");
        dataSource.setPassword("sa");

        return dataSource;
    }
    
    // 配置entityManagerFactory
    // 配置transactionManager
    // 配置额外Hibernate属性
}

在测试类中激活test profile:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {
  Application.class, 
  H2TestProfileJPAConfig.class})
@ActiveProfiles("test")
public class SpringBootProfileIntegrationTest {
    // 测试代码同上
}

6. 结论

本文介绍了在Spring中为测试配置独立数据源的三种主流方案:

标准属性文件覆盖(Spring Boot默认机制)
自定义属性文件(灵活性强)
Spring Profiles(环境隔离最佳实践)

⚠️ 踩坑提醒:测试数据源配置错误可能导致测试环境污染生产数据库,务必确保测试配置与生产环境隔离。

完整示例代码请参考GitHub仓库