2020
Jul
10

h2database 是一個 Java base database ,這篇文章主要是介紹如何使用 h2database 來做 MySQL Unit Test ,網路上可以找到很多種寫 MySQL unit test 的工具,有些非常笨重光是起 MySQL server 就花掉好幾分鐘,而我使用 h2database 後覺得非常不錯,執行超級快速。

h2database 官方提供的各種 database 比較。

H2 Derby HSQLDB MySQL PostgreSQL
Pure Java Yes Yes Yes No No
Memory Mode Yes Yes Yes No No
Encrypted Database Yes Yes Yes No No
ODBC Driver Yes No No Yes Yes
Fulltext Search Yes No No Yes Yes
Multi Version Concurrency Yes No Yes Yes Yes
Footprint (embedded) ~2 MB ~3 MB ~1.5 MB
Footprint (client) ~500 KB ~600 KB ~1.5 MB ~1 MB ~700 KB

h2database 有三種模式,分別是 in-memory, embedded, Server,這篇文章只說明如何使用 in-memory mode & MyBatis 來跑 unit test。

首先在 pom.xml 加入 h2 dependency 。

Example
  1. <dependency>
  2. <groupId>com.h2database</groupId>
  3. <artifactId>h2</artifactId>
  4. <version>1.4.200</version>
  5. <scope>test</scope>
  6. </dependency>

搭配 MyBatis

MyBatis config.xml 加入以下設定, jdbc:h2:mem 代表使用 in-memory mode ,;DB_CLOSE_DELAY=1 這個參數是指當 connection 斷掉後保留 db 的資料,不要清空,如果沒有加這個值 connection 一斷,下次再連線就會發現資料不見了。

Example
  1. <environments>
  2. <environment id="unitTest">
  3. <transactionManager type="JDBC">
  4. <property name="" value="" />
  5. </transactionManager>
  6. <dataSource type="POOLED">
  7. <property name="driver" value="org.h2.Driver" />
  8. <property name="url" value="jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1" />
  9. <property name="username" value="root" />
  10. <property name="password" value=""/>
  11. </dataSource>
  12. </environment>
  13. </environments>

Java Code 如下,如果我們是使用 in-memory mode, session

Example
  1. public class H2database {
  2.  
  3. private static SqlSessionFactory sqlSessionFactory = null;
  4. // keep session
  5. private static SqlSession session = null;
  6.  
  7. public void startServer() throws Exception {
  8. Reader reader = Resources.getResourceAsReader(
  9. "mybatis.xml"
  10. );
  11. if (null == sqlSessionFactory) {
  12. sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader, "unitTest");
  13. Connection conn = null;
  14. try {
  15. session = sqlSessionFactory.openSession();
  16. conn = session.getConnection();
  17. ScriptRunner runner = new ScriptRunner(conn);
  18. runner.setLogWriter(null);
  19. FileReader r = new FileReader(unitSql);
  20. runner.runScript(r);
  21. } finally {
  22. if (null != reader) reader.close();
  23. }
  24. }
  25. }

mock close method,目前不知道為什麼,我已經有加 ;DB_CLOSE_DELAY=-1, testing code 中有 close session 是不會清空資料,但是如果被測試的 object 有做 session close 的動作,還是會發生資料不見的問題,只好 mock close = doNothing 解掉這個問題。

Example
  1. doNothing().when(session).close();

搭配 Java JDBC

Example
  1. DriverManager.registerDriver(new org.h2.Driver());
  2. conn = DriverManager.getConnection("jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=FALSE", "root", "");
  3.  
  4. // To create table
  5. String query = String.join("",
  6. "CREATE TABLE IF NOT EXISTS `tableName` (",
  7. "`id` varchar(16) NOT NULL,",
  8. "`name` varchar(64) NOT NULL,",
  9. "PRIMARY KEY (`id`,`name`)",
  10. ");");
  11. PreparedStatement pstmt = conn.prepareStatement(query);
  12. pstmt.execute();
  13.  
  14.  
  15. // To insert data
  16.  
  17. String query = String.format("insert into `%s` (`id`, `name`) values ('%s', '%s')", table, id, name);
  18. PreparedStatement pstmt = conn.prepareStatement(query);
  19. pstmt.execute();

回應 (Leave a comment)