Testcontainer-03篇 MySQL

本文介绍如何使用TestContainer简化后端项目中MySQL数据库的测试过程,包括依赖引入、启动MySQL容器、配置数据库连接及使用特殊URL进行数据库初始化的方法。

通常我们的后端项目中都离不开数据库的使用,然而在编写测试用例的时候却不是很好处理,这个时候,我们可以利用TestContainer来进行数据库的测试支持,这里使用我熟悉的MySQL。

一、引入依赖

<dependency>
   <groupId>org.testcontainers</groupId>
   <artifactId>testcontainers</artifactId>
   <version>1.12.0</version>
 </dependency>
<dependency>
   <groupId>org.mybatis.spring.boot</groupId>
   <artifactId>mybatis-spring-boot-starter</artifactId>
   <version>1.3.2</version>
 </dependency>
 <dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
 </dependency>
 <dependency>
   <groupId>org.testcontainers</groupId>
   <artifactId>mysql</artifactId>
   <version>1.12.0</version>
   <scope>test</scope>
 </dependency>

其中mybatis是我这里用到的一个持久层框架,大家根据自己的需要配置

二、使用testcontainer启动mysql

使用testcontainer启动mysql有两种方式:

  1. 使用注解@ClassRule / @Rule
  2. 使用特殊的url连接

首先,我们写出公用的代码,如下:
User类:

package com.firewolf.utils.testcontainer.mysql;

import lombok.Data;

@Data
public class User {

  private Integer id;
  private String name;
  private Integer age;
}

UserMapper接口:

package com.firewolf.utils.testcontainer.mysql;

import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

@Mapper
public interface UserMapper {

  @Select("select * from user")
  List<User> findUser();
}

(一)使用注解的方式

一般情况下,@Rule用处不是很大,因为这个只能在测试用例里面单独的使用,而不能注入到Spring容器中,所以我这里只记录@ClassRule用法

  1. 在类加载前启动容器
      @ClassRule
      public static MySQLContainer mysql = (MySQLContainer) new MySQLContainer("mysql:5.7")
          .withInitScript("db/init.sql");
    
    这里引入了初始化脚本(如果你有初始的数据库脚本),脚本所在目录为resources下面
    init.sql内容如下:
    CREATE TABLE `user` (
                            `name` varchar(255) DEFAULT NULL,
                            `age` int(11) DEFAULT NULL,
                            `id` int(11) NOT NULL AUTO_INCREMENT,
                            PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    insert into `user` (`name`,`age`) values ('lisi',30);
    insert into `user` (`name`,`age`) values ('wangwu',30);
    insert into `user` (`name`,`age`) values ('赵六',15);
    
    
  2. 为Spring容器注入连接属性
    @BeforeClass
    public static void init() {
      System.setProperty("spring.datasource.url", mysql.getJdbcUrl());
      System.setProperty("spring.datasource.driver-class-name", mysql.getDriverClassName());
      System.setProperty("spring.datasource.username", mysql.getUsername());
      System.setProperty("spring.datasource.password", mysql.getPassword());
    }
    
    这样的话,Spring在初始化数据源的时候,就能够连接上数据库
  3. 注入UserMapper并使用
      @Autowired
      private UserMapper userMapper;
      @Test
      public void testUserMapper() {
        List<User> userList = userMapper.findUser();
        assert userList.size() == 3;
        System.out.println("查询到的用户列表如下:");
        System.out.println(userList);
      }
    
  4. 完整代码为
    package com.firewolf.utils.testcontainer.mysql;
    
    import com.firewolf.utils.testcontainer.TestcontainerApplication;
    import java.util.List;
    import org.junit.BeforeClass;
    import org.junit.ClassRule;
    import org.junit.Ignore;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit4.SpringRunner;
    import org.testcontainers.containers.MySQLContainer;
    @SpringBootTest(classes = TestcontainerApplication.class)
    @RunWith(SpringRunner.class)
    public class MySQLDriver2 {
      @Autowired
      private UserMapper userMapper;
    
      @ClassRule
      public static MySQLContainer mysql = (MySQLContainer) new MySQLContainer("mysql:5.7")
          .withInitScript("db/init.sql");
      /**
       * 设置数据库连接属性
       */
      @BeforeClass
      public static void init() {
        System.setProperty("spring.datasource.url", mysql.getJdbcUrl());
        System.setProperty("spring.datasource.driver-class-name", mysql.getDriverClassName());
        System.setProperty("spring.datasource.username", mysql.getUsername());
        System.setProperty("spring.datasource.password", mysql.getPassword());
      }
    
      @Test
      public void testUserMapper() {
        List<User> userList = userMapper.findUser();
        assert userList.size() == 3;
        System.out.println("查询到的用户列表如下:");
        System.out.println(userList);
      }
    }
    

这种用法的话,在Spring配置文件中不需要配置数据库连接的四个关键属性,其他的可以自行配置;

如果只是在某个测试用例里面用到数据库,我们可以直接在测试用例里面启动mysql容器即可,如:

public void testSimple() {
  MySQLContainer mysql = (MySQLContainer) new MySQLContainer("mysql:5.7")
      .withInitScript("db/init.sql");
  mysql.start();

  System.out.println(mysql.getJdbcUrl());
  System.out.println(mysql.getDriverClassName());
  System.out.println(mysql.getUsername());
  System.out.println(mysql.getPassword());

}

(二)使用特殊的URL

这种方式的测试用例类非常简答,没有任何容器相关内容,先贴出来:

package com.firewolf.utils.testcontainer.mysql;

import com.firewolf.utils.testcontainer.TestcontainerApplication;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;


@SpringBootTest(classes = TestcontainerApplication.class)
@RunWith(SpringRunner.class)
public class MySQLDriver {

  @Autowired
  private UserMapper userMapper;

  @Test
  public void test() {
    List<User> userList = userMapper.findUser();
    assert userList.size() == 3;
    System.out.println("查询到的用户列表如下:");
    System.out.println(userList);
  }
}

那么怎么引入testcontainer呢,其实很简答,就在我们的配置文件中对url进行处理,如下:

#mysql
spring.datasource.driver-class-name=org.testcontainers.jdbc.ContainerDatabaseDriver
spring.datasource.url=jdbc:tc:mysql:5.7://localhost:3306/testdb?TC_INITSCRIPT=db/init.sql
spring.datasource.username=root
spring.datasource.password=111111
#mybatis下划线转驼峰命名
mybatis.configuration.map-underscore-to-camel-case=true

我们可以看到,和正常配置URL不同的是,这里在jdbc后面添加了tc
同时我们还看到,可以通过TC_INITSCRIPT来指定初始化脚本的位置;

对于URL这种方式,我们还可以使用类来进行数据库初始化,方式如下:

  1. 改变URL为:
    spring.datasource.url=jdbc:tc:mysql:5.7://localhost:3306/testdb?TC_INITFUNCTION=com.firewolf.utils.testcontainer.mysql.DataSourceInit::initFunction
    
    这里使用TC_INITFUNCTION来指定了初始化的类和方法
  2. 编写初始化方法
    package com.firewolf.utils.testcontainer.mysql;
    
    import java.sql.Connection;
    import java.sql.SQLException;
    import java.sql.Statement;
    import java.util.Arrays;
    
    public class DataSourceInit {
    
      public static void initFunction(Connection connection) throws Exception {
        Statement statement = connection.createStatement();
    
        String[] sqls = new String[]{
    
            "CREATE TABLE `user` (\n"
                + "                        `name` varchar(255) DEFAULT NULL,\n"
                + "                        `age` int(11) DEFAULT NULL,\n"
                + "                        `id` int(11) NOT NULL AUTO_INCREMENT,\n"
                + "                        PRIMARY KEY (`id`)\n"
                + ") ENGINE=InnoDB DEFAULT CHARSET=utf8",
            "insert into `user` (`name`,`age`) values ('bajie',30)",
            "insert into `user` (`name`,`age`) values ('wukong',1000)",
            "insert into `user` (`name`,`age`) values ('唐僧',600)",
        };
    
        Arrays.stream(sqls).forEach(x -> {
          try {
            statement.execute(x);
          } catch (SQLException e) {
            e.printStackTrace();
          }
        });
      }
    }
    
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值