Java SE環境中測試JPA實體的簡單方法
Java SE環境中測試JPA實體的簡單方法
出於軟件質量的考慮,理論上來說我們寫的一切代碼都要經過測試。JPA的測試不像普通的組件那麽方便,因為JPA涉及到數據庫,所以集成測試必不可少,像Arquillian這樣的測試框架能處理比較復雜的集成測試,但是它的配置相對也更復雜一點,所以本篇文章主要講一下在Java SE環境中較簡單地測試JPA實體(Entity)的方法。
我們需要實現的目標有:1.不需要mysql這樣需要額外安裝的數據庫;2.在SE環境中可以直接測試。
相關工具我們主要用到JUnit,Maven。相關源碼參考我的github倉庫。
添加依賴
在pom.xml
中添加如下依賴:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.196</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.1-api</artifactId>
<version>1.0.2.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.10.Final</version>
</dependency>
我們用到了h2數據庫,jpa2.1-api以及hibernate。
JPA實體
假設我們要測試的實體為這樣(省略了getter/setter):
src/main/java/com/github/holyloop/entity/Book.java
@Entity
@Table(name = "book")
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(unique = true, nullable = false)
private Long id;
@Column(nullable = false)
private String title;
@Column(nullable = false)
private String author;
}
持久化單元
在測試資源中添加持久化單元聲明:
src/test/resources/META-INF/persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="test" transaction-type="RESOURCE_LOCAL">
<class>com.github.holyloop.entity.Book</class>
<properties>
<!-- Configuring JDBC properties -->
<property name="javax.persistence.jdbc.url"
value="jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;INIT=RUNSCRIPT FROM ‘classpath:create.sql‘\;
RUNSCRIPT FROM ‘classpath:data.sql‘" />
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver" />
<!-- Hibernate properties -->
<property name="hibernate.archive.autodetection" value="class, hbm" />
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
<property name="hibernate.format_sql" value="true" />
<property name="hibernate.show_sql" value="true" />
</properties>
</persistence-unit>
</persistence>
這裏給持久化單元命名為test
,添加了h2數據庫驅動,並且聲明了幾個hibernate專有的屬性,它們將輸出一些
格式化的調試信息方便排查問題。
測試類
SQL
首先我們來添加幾個sql文件:
src/test/resources/create.sql
:
-- book
drop table if exists `book`;
create table book (
id bigint(20) unsigned not null auto_increment,
title varchar(50) not null,
author varchar(20) not null,
primary key (id)
);
src/test/resources/data.sql
:
DELETE FROM book;
INSERT INTO book(id, title, author) VALUES (1, ‘Spring in Action‘, ‘Craig Walls‘);
當然你也可以在persistence.xml
中聲明:
<property name="hibernate.hbm2ddl.auto" value="create-drop" />
而不用create.sql文件。上面這個屬性將會自動地將我們的Entity聲明轉換為對應的ddl,並且結束後會刪除數據
。我這邊用create.sql只是出於個人喜好。
data.sql中可以隨意地插入測試數據。
Java
先看看我們的基本測試類:
src/test/java/com/github/holyloop/entity/BaseTest.java
:
protected static EntityManagerFactory emf;
protected static EntityManager em;
@BeforeClass
public static void init() {
emf = Persistence.createEntityManagerFactory("test");
em = emf.createEntityManager();
}
@AfterClass
public static void tearDown() {
em.clear();
em.close();
emf.close();
}
這裏聲明了實體管理器工廠emf和實體管理器em,init
和tearDown
分別在測試類初始化和銷毀時執行,init負
責初始化實體管理器em,tearDown則釋放對應資源。我們繼續在基本測試類中添加如下方法:
@Before
public void initDB() {
Session session = em.unwrap(Session.class);
session.doWork(new Work() {
@Override
public void execute(Connection connection) throws SQLException {
try {
File script = new File(getClass().getResource("/data.sql").getFile());
RunScript.execute(connection, new FileReader(script));
} catch (FileNotFoundException e) {
throw new RuntimeException("could not initialize with script");
}
}
});
}
@After
public void clean() {
em.clear();
}
這樣我們的所有子類測試方法在開始之前都會預加載data.sql
中的數據,並且結束後實體管理器將清除掉持久化上下文,這樣保證測試方法之間不會互相影響。
接下來我們實現一個簡單的測試:
src/test/java/com/github/holyloop/entity/BookTest.java
:
public class BookTest extends BaseTest {
@Test
public void testAddBook() {
Book book = new Book();
book.setTitle("new book");
book.setAuthor("new author");
em.getTransaction().begin();
em.persist(book);
em.getTransaction().commit();
@SuppressWarnings("rawtypes")
List books = em.createQuery("select b from Book b").getResultList();
assertEquals(2, books.size());
}
@Test
public void testQueryBook() {
Book book = em.find(Book.class, 1L);
assertNotNull(book);
}
}
BookTest
繼承了我們上面實現的基本測試類,這裏我實現了兩個基本測試,testAddBook
測試能否成功添加一本新書,testQueryBook
測試能否查找到我們在data.sql
中插入的測試數據。
測試
測試用例編寫完畢之後可以開始測試了,進入到你的項目根目錄,some-path/your-project
:
執行:
mvn clean test
如果一切正常,測試結果如下:
以上就是不額外安裝數據庫,不依賴其他容器的測試JPA實體的方法。
Java SE環境中測試JPA實體的簡單方法