分类
Spring Data Testing

为spring应用单独配置测试环境数据库

Configuring Separate Spring DataSource for Tests

1. 概述

很多Spring应用都需要关联数据库。而每次跑测试都对接真实的数据库有时候会让我们很头疼,所以如何在测试的环境中摒弃生产环境下的数据库而取而代之地使用一种更快、更小、对环境依赖程度更小的数据库便成为了急待解决的问题。

本文中将介绍几种为测试环境配置单独的数据库的方案。

注意:其实这里用『数据库(database)』并不正确,正确的说法应该是数据源(data source)。鉴于习惯,本文中使用了数据库来替待了数据源

2. MAVEN依赖

在正式编码之间,我们首先创建一个基本的Spring Boot Data项目,pom.xml文件如下:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<dependency>
	<groupId>com.h2database</groupId>
	<artifactId>h2</artifactId>
	<scope>runtime</scope>
</dependency>
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<scope>runtime</scope>
</dependency>

如上我们添加了Data JPA依赖以及H2数据库、mysql数据库依赖。

3. 项目配置

在Spring Boot项目中,默认的配置文件为:src/main/resources/application.properties。我们打开此文件并将项目的数据库配置为mysql:

spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/db_example
spring.datasource.username=root

此时若运行本应用,则需要有一个服务于3306端口的本机数据库支持,用户名为root,密码为空,且存在db_example数据库。如果不存在满足以上条件的数据库,系统启动时便会发生一个异常。

4. 测试配置

与运行环境下生效的src/main/resources/application.properties文件对应,在测试文件夹中还可以存在(不存在的话手动建立即可)一个src/test/resources/application.properties文件,该文件只 在测试时起作用。在运行单元测试时,Spring首先查找src/test/resources/application.properties文件,如果存在则使用该文件做配置文件,如果不存在再去main目录下查找application.properties文件。

比如声明在测试中使用h2数据库,则可以在src/test/resources/application.properties文件中添加如下配置项:

spring.datasource.url=jdbc:h2:mem:db_example

此时,在运行测试时Spring应用便自动启用h2数据源且同时创建db_example数据库。所以即使没有满足生产环境配置下的数据库,测试也同样可以启动成功。

5. 自定义测试配置文件

除了直接在src/test/resources/application.properties文件中进行测试配置以外,还可以在单元测试中指定自定义配置文件。

比如新建src/main/resources/h2datasource.properties文件:

jdbc.url=jdbc:h2:mem:db_example
jdbc.username=root
jdbc.password=

接下来便可以根据该文件来创建一个Bean返回数据库信息了:

@Configuration
@PropertySource("classpath:h2datasource.properties")
@Profile("default")
public class H2DataSourceConfig {

    @Autowired
    Environment environment;

    /**
     * 定义数据源
     *
     * @return
     */
    @Bean
    DataSource dataSource() {
        DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
        dataSourceBuilder.url(this.environment.getProperty("jdbc.url"));
        dataSourceBuilder.username(this.environment.getProperty("jdbc.user"));
        dataSourceBuilder.password(this.environment.getProperty("jdbc.password"));
        return dataSourceBuilder.build();
    }
}

单元测试时,可以在@SpringBootTest中指定该配置文件来启用该配置文件:

@SpringBootTest(classes = {SpringTestingSeparateDataSourceApplication.class,
        H2DataSourceConfig.class})
public class H2DataSourceConfigTest {
    @Autowired
    StudentRepository studentRepository;

    @Test
    void contextLoads() {
        this.studentRepository.findAll();
    }
}

当然了,我们同样可以在src/test/resources/建立与src/main/resources/中的同名文件。然后就像上一小节一样,一个用于测试环境,另一个用于生产环境。这本节中在@SpringBootTest中指定测试文件并不冲突。

注意:自定义配置文件并不属于本文的重点,你可以点击使用内存数据库进行独立测试来了解更多的内容。

6. 使用Spring Profiles

还可以在单元测试中指定特定的Profile情景,以达到在某个单元测试中启用测试数据库的目的:

@SpringBootTest(classes = {
        SpringTestingSeparateDataSourceApplication.class,
        H2ProfileJPAConfig.class
})
@ActiveProfiles("test")
class H2ProfileJPAConfigTest {
    @Autowired
    StudentRepository studentRepository;

    @Test
    void dataSource() {
        this.studentRepository.findAll();
    }
}

@ActiveProfiles("test")表明:运行该单元测试时,强行使用test情景。

除了可以在项目配置文件(application.properties)中声明profile情景以外,还可以在使用@Profile注解

@Configuration
@Profile("test")
public class H2ProfileJPAConfig {

    /**
     * 定义数据源
     * @return
     */
    @Bean
    @Profile("test")
    public DataSource dataSource() {
        DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
        dataSourceBuilder.url("jdbc:h2:mem:db_example");
        dataSourceBuilder.username("root");
        dataSourceBuilder.password("");
        return dataSourceBuilder.build();
    }
}

上述两段代码结合在一起便实现了:当运行H2ProfileJPAConfigTest时强行使用test情景,近而启用了test情景下的h2内存数据库进行单元测试。

7. 总结

在测试中使用内存数据库将减小项目的配置难度,可以更快的运行测试。内存数据库与项目的依赖环境相同,从而不必为了测试项目而单独建立一个数据库。当我们同时负责多个项目,而每个项目生产环境的数据库版本都不相同时,使用内存数据库跑测试将事半功倍。同时由于内存数据库又小又轻,相较于搭建生产环境下使用的数据库而言,它还可以节省一些计算机资源。