博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring、Spring Boot和TestNG测试指南 - 测试关系型数据库
阅读量:5968 次
发布时间:2019-06-19

本文共 6030 字,大约阅读时间需要 20 分钟。

提供了对,能够让我们很方便对关系型数据库做集成测试。

同时Spring Boot提供了和的支持,能够方便的管理开发过程中产生的SQL文件,配合Spring已经提供的工具能够更方便地在测试之前初始化数据库以及测试之后清空数据库。

本章节为了方便起见,本章节使用了H2作为测试数据库。

注意:在真实的开发环境中,集成测试用数据库应该和最终的生产数据库保持一致,这是因为不同数据库的对于SQL不是完全相互兼容的,如果不注意这一点,很有可能出现集成测试通过,但是上了生产环境却报错的问题。

因为是集成测试,所以我们使用了maven-failsafe-plugin来跑,它和maven-surefire-plugin的差别在于,maven-failsafe-plugin只会搜索*IT.java来跑测试,而maven-surefire-plugin只会搜索*Test.java来跑测试。

如果想要在maven打包的时候跳过集成测试,只需要mvn clean install -DskipITs

被测试类

先介绍一下被测试的类。

public class Foo {  private String name;  public String getName() {    return name;  }  public void setName(String name) {    this.name = name;  }}

@Repositorypublic class FooRepositoryImpl implements FooRepository {  private JdbcTemplate jdbcTemplate;  @Override  public void save(Foo foo) {    jdbcTemplate.update("INSERT INTO FOO(name) VALUES (?)", foo.getName());  }  @Override  public void delete(String name) {    jdbcTemplate.update("DELETE FROM FOO WHERE NAME = ?", name);  }  @Autowired  public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {    this.jdbcTemplate = jdbcTemplate;  }}

例子1:不使用Spring Testing提供的工具

@Configuration@ComponentScan(basePackageClasses = FooRepository.class)public class Spring_1_IT_Configuration {  @Bean(destroyMethod = "shutdown")  public DataSource dataSource() {    return new EmbeddedDatabaseBuilder()        .generateUniqueName(true)        .setType(EmbeddedDatabaseType.H2)        .setScriptEncoding("UTF-8")        .ignoreFailedDrops(true)        .addScript("classpath:me/chanjar/domain/foo-ddl.sql")        .build();  }  @Bean  public JdbcTemplate jdbcTemplate() {    return new JdbcTemplate(dataSource());  }}

Spring_1_IT_Configuration中,我们定义了一个H2的DataSource Bean,并且构建了JdbcTemplate Bean。

注意看addScript("classpath:me/chanjar/domain/foo-ddl.sql")这句代码,我们让EmbeddedDatabase执行脚本来建表:

CREATE TABLE FOO (  name VARCHAR2(100));

@ContextConfiguration(classes = Spring_1_IT_Configuration.class)public class Spring_1_IT extends AbstractTestNGSpringContextTests {  @Autowired  private FooRepository fooRepository;  @Autowired  private JdbcTemplate jdbcTemplate;  @Test  public void testSave() {    Foo foo = new Foo();    foo.setName("Bob");    fooRepository.save(foo);    assertEquals(        jdbcTemplate.queryForObject("SELECT count(*) FROM FOO", Integer.class),        Integer.valueOf(1)    );  }  @Test(dependsOnMethods = "testSave")  public void testDelete() {    assertEquals(        jdbcTemplate.queryForObject("SELECT count(*) FROM FOO", Integer.class),        Integer.valueOf(1)    );    Foo foo = new Foo();    foo.setName("Bob");    fooRepository.save(foo);    fooRepository.delete(foo.getName());    assertEquals(        jdbcTemplate.queryForObject("SELECT count(*) FROM FOO", Integer.class),        Integer.valueOf(0)    );  }}

在这段测试代码里可以看到,我们分别测试了FooRepositorysavedelete方法,并且利用JdbcTemplate来验证数据库中的结果。

例子2:使用Spring Testing提供的工具

在这个例子里,我们会使用来辅助测试。

@Configuration@ComponentScan(basePackageClasses = FooRepository.class)public class Spring_2_IT_Configuration {  @Bean  public DataSource dataSource() {    EmbeddedDatabase db = new EmbeddedDatabaseBuilder()        .generateUniqueName(true)        .setType(EmbeddedDatabaseType.H2)        .setScriptEncoding("UTF-8")        .ignoreFailedDrops(true)        .addScript("classpath:me/chanjar/domain/foo-ddl.sql")        .build();    return db;  }  @Bean  public JdbcTemplate jdbcTemplate() {    return new JdbcTemplate(dataSource());  }  @Bean  public PlatformTransactionManager transactionManager() {    return new DataSourceTransactionManager(dataSource());  }}

这里和例子1的区别在于,我们提供了一个PlatformTransactionManager Bean,这是因为在下面的测试代码里的AbstractTransactionalTestNGSpringContextTests需要它。

@ContextConfiguration(classes = Spring_2_IT_Configuration.class)public class Spring_2_IT extends AbstractTransactionalTestNGSpringContextTests {  @Autowired  private FooRepository fooRepository;  @Test  public void testSave() {    Foo foo = new Foo();    foo.setName("Bob");    fooRepository.save(foo);    assertEquals(countRowsInTable("FOO"), 1);    countRowsInTableWhere("FOO", "name = 'Bob'");  }  @Test(dependsOnMethods = "testSave")  public void testDelete() {    assertEquals(countRowsInTable("FOO"), 0);    Foo foo = new Foo();    foo.setName("Bob");    fooRepository.save(foo);    fooRepository.delete(foo.getName());    assertEquals(countRowsInTable("FOO"), 0);  }}

在这里我们使用countRowsInTable("FOO")来验证数据库结果,这个方法是AbstractTransactionalTestNGSpringContextTestsJdbcTestUtils的代理。

而且要注意的是,每个测试方法在执行完毕后,会自动rollback,所以在testDelete的第一行里,我们assertEquals(countRowsInTable("FOO"), 0),这一点和例子1里是不同的。

更多关于Spring Testing Framework与Transaction相关的信息,可以见Spring官方文档 。

例子3:使用Spring Boot

@SpringBootTest@SpringBootApplication(scanBasePackageClasses = FooRepository.class)public class Boot_1_IT extends AbstractTransactionalTestNGSpringContextTests {  @Autowired  private FooRepository fooRepository;  @Test  public void testSave() {    Foo foo = new Foo();    foo.setName("Bob");    fooRepository.save(foo);    assertEquals(countRowsInTable("FOO"), 1);    countRowsInTableWhere("FOO", "name = 'Bob'");  }  @Test(dependsOnMethods = "testSave")  public void testDelete() {    assertEquals(countRowsInTable("FOO"), 0);    Foo foo = new Foo();    foo.setName("Bob");    fooRepository.save(foo);    fooRepository.delete(foo.getName());    assertEquals(countRowsInTable("FOO"), 0);  }    @AfterTest  public void cleanDb() {    flyway.clean();  }  }

因为使用了Spring Boot来做集成测试,得益于其AutoConfiguration机制,不需要自己构建DataSourceJdbcTemplatePlatformTransactionManager的Bean。

并且因为我们已经将flyway-core添加到了maven依赖中,Spring Boot会利用flyway来帮助我们初始化数据库,我们需要做的仅仅是将sql文件放到classpath的db/migration目录下:

V1.0.0__foo-ddl.sql:

CREATE TABLE FOO (  name VARCHAR2(100));

而且在测试最后,我们利用flyway清空了数据库:

@AfterTestpublic void cleanDb() {  flyway.clean();}

使用flyway有很多好处:

  1. 每个sql文件名都规定了版本号

  2. flyway按照版本号顺序执行

  3. 在开发期间,只需要将sql文件放到db/migration目录下就可以了,不需要写类似EmbeddedDatabaseBuilder.addScript()这样的代码

  4. 基于以上三点,就能够将数据库初始化SQL语句也纳入到集成测试中来,保证代码配套的SQL语句的正确性

  5. 可以帮助你清空数据库,这在你使用非内存数据库的时候非常有用,因为不管测试前还是测试后,你都需要一个干净的数据库

参考文档

本章节涉及到的Spring Testing Framework JDBC、SQL相关的工具:

和flyway相关的:

转载地址:http://ppqax.baihongyu.com/

你可能感兴趣的文章
Pycharm选择pyenv安装的Python版本
查看>>
?Sized 和 Sized
查看>>
Java中如何防止内存泄漏的发生
查看>>
Java中Int转byte分析
查看>>
滑动窗口最大值的golang实现
查看>>
初学Phreeze 3
查看>>
会计的思考(17):还原会计报表的企业个性之一
查看>>
java对象初始化顺序的简单验证
查看>>
[CF452E]Three strings
查看>>
获取指定进程所对应的可执行(EXE)文件全路径(代码)
查看>>
【jQuery实例】Ajax登录页面
查看>>
ORA-01722:无效数字
查看>>
搭建golang+vscode开发环境
查看>>
C#占位符
查看>>
java面试-JVM调优和参数配置
查看>>
php简单实现二级联动
查看>>
angular4 辅助路由
查看>>
解决Eclipse java build path中Web App Libraries无法自动找到WEB-INF的lib目录
查看>>
Linux(centos)系统各个目录的作用详解
查看>>
python廖雪峰教程 学习笔记
查看>>