文件

§使用資料庫進行測試

雖然可以撰寫 功能測試,透過啟動包含資料庫的完整應用程式來測試資料庫存取程式碼,但由於啟動完整應用程式會啟動並執行更多元件,只為了測試應用程式的其中一小部分,因此通常不建議這麼做。

Play 提供許多公用程式,協助測試資料庫存取程式碼,讓程式碼可以在與應用程式隔離的狀態下使用資料庫進行測試。這些公用程式可以輕鬆地搭配 ScalaTestspecs2 使用,而且可以讓資料庫測試更接近輕量且快速執行的單元測試,而不是負擔較重且執行速度較慢的功能測試。

§使用資料庫

要使用資料庫後端進行測試,您只需要

libraryDependencies += javaJdbc % Test

要連線到資料庫,至少需要資料庫驅動程式名稱和資料庫的 URL,使用 Database 靜態工廠方法。例如,要連線到 MySQL,可以使用下列範例

Database database =
    Databases.createFrom("com.mysql.jdbc.Driver", "jdbc:mysql://127.0.0.1/test");

這會為執行於 localhost 上的 MySQL test 資料庫建立一個資料庫連線池,名稱為 default。資料庫名稱僅由 Play 內部使用,例如,由其他功能(例如演化)用於載入與該資料庫相關的資源。

您可能想要為資料庫指定其他設定,包括自訂名稱或設定屬性(例如使用者名稱、密碼和 Play 支援的各種連線池設定項目),方法是提供自訂名稱參數和/或自訂設定參數

Database database =
    Databases.createFrom(
        "mydatabase",
        "com.mysql.jdbc.Driver",
        "jdbc:mysql://127.0.0.1/test",
        ImmutableMap.of(
            "username", "test",
            "password", "secret"));

使用資料庫後,由於資料庫通常由持有開啟連線且可能也有執行緒的連線池作為後盾,因此您需要關閉它。這可透過呼叫 shutdown 方法來完成

database.shutdown();

這些方法特別有用,如果您將它們與 JUnit 的 @Before@After 註解結合使用,例如

Database database;

@Before
public void createDatabase() {
  database = Databases.createFrom("com.mysql.jdbc.Driver", "jdbc:mysql://127.0.0.1/test");
}

@After
public void shutdownDatabase() {
  database.shutdown();
}

提示:您可以使用此方法將測試資料庫設定外部分派,使用環境變數或系統屬性來設定要使用的資料庫以及如何連線到它。這讓開發人員可以彈性地設定自己的環境,以及讓 CI 系統提供可能與開發不同的特定環境。

§使用內部記憶體資料庫

有些人偏好不要安裝資料庫等基礎架構來執行測試。Play 提供簡單的輔助程式,用於為這些目的建立 H2 內部記憶體資料庫

Database database = Databases.inMemory();

可透過提供自訂名稱、自訂 URL 參數和自訂連線池組態來設定記憶體中資料庫。以下顯示提供 MODE 參數來告知 H2 模擬 MySQL,以及設定連線池以記錄所有陳述式

Database database =
    Databases.inMemory(
        "mydatabase", ImmutableMap.of("MODE", "MYSQL"), ImmutableMap.of("logStatements", true));

與一般資料庫工廠一樣,請務必隨時關閉記憶體中資料庫連線池

database.shutdown();

§套用演化

執行測試時,通常會希望資料庫管理資料庫結構。如果您已在測試中使用演化,通常會重複使用在開發和製作中使用的相同演化。您可能還想建立專門用於測試的自訂演化。Play 提供一些方便的輔助程式,可套用和管理演化,而無需執行整個 Play 應用程式。

若要套用演化,您可以從 Evolutions 靜態類別使用 applyEvolutions

Evolutions.applyEvolutions(database);

這將從 evolutions/<databasename> 目錄中的類別路徑載入演化,並套用它們。

測試執行完畢後,您可能想將資料庫重設為原始狀態。如果您已實作演化縮寫指令碼,以便刪除所有資料庫表格,則只要呼叫 cleanupEvolutions 方法即可

Evolutions.cleanupEvolutions(database);

§自訂演化

在某些情況下,您可能想在測試中執行一些自訂演化。可以使用自訂 EvolutionsReader 使用自訂演化。最簡單的方法是使用 Evolutions 上的靜態工廠方法,例如 forDefault 會為預設資料庫建立簡單的 Evolution 指令碼清單的演化讀取器。例如

Evolutions.applyEvolutions(
    database,
    Evolutions.forDefault(
        new Evolution(
            1,
            "create table test (id bigint not null, name varchar(255));",
            "drop table test;")));

清理自訂演化的方式與清理一般演化的方式相同,使用 cleanupEvolutions 方法

Evolutions.cleanupEvolutions(database);

但請注意,您不需要在此傳遞自訂演化讀取器,這是因為演化的狀態儲存在資料庫中,包括會用來移除資料庫的下降腳本。

有時將自訂演化腳本放入程式碼中會不切實際。如果是這樣,您可以使用 fromClassLoader 工廠方法將它們放入測試資源目錄中

Evolutions.applyEvolutions(
    database, Evolutions.fromClassLoader(getClass().getClassLoader(), "testdatabase/"));

這會從 testdatabase/evolutions/<databasename>/<n>.sql 載入演化,其結構和格式與開發和製作時所做的相同。

如果您將演化腳本儲存在專案資料夾外,可以使用 EnvironmentEvolutionsReader 從檔案系統上的絕對路徑或從專案資料夾中看到的相對路徑載入腳本

import play.Environment;
import play.api.db.evolutions.EnvironmentEvolutionsReader;

// Absolute path
Evolutions.applyEvolutions(
    database,
    new EnvironmentEvolutionsReader(Environment.simple().asScala(), "/opt/db_migration"));

// Relative path (based on your project's root folder)
Evolutions.applyEvolutions(
    database,
    new EnvironmentEvolutionsReader(Environment.simple().asScala(), "../db_migration"));

§與 JUnit 整合

通常您會有很多測試要使用相同的演化執行,因此將演化設定程式碼萃取到之前和之後的方法中,連同資料庫設定和移除程式碼是有意義的。以下是完整測試可能的外觀

import static org.junit.Assert.*;

import java.sql.Connection;
import org.junit.*;
import play.db.Database;
import play.db.Databases;
import play.db.evolutions.*;

public class DatabaseTest {

  Database database;

  @Before
  public void setupDatabase() {
    database = Databases.inMemory();
    Evolutions.applyEvolutions(
        database,
        Evolutions.forDefault(
            new Evolution(
                1,
                "create table test (id bigint not null, name varchar(255));",
                "drop table test;")));
  }

  @After
  public void shutdownDatabase() {
    Evolutions.cleanupEvolutions(database);
    database.shutdown();
  }

  @Test
  public void testDatabase() throws Exception {
    Connection connection = database.getConnection();
    connection.prepareStatement("insert into test values (10, 'testing')").execute();

    assertTrue(
        connection.prepareStatement("select * from test where id = 10").executeQuery().next());
  }
}

下一步:測試網路服務客戶端


在此文件發現錯誤?此頁面的原始碼可以在 這裡 找到。在閱讀 文件指南 後,請隨時提交拉取請求。有任何問題或建議想分享?請前往 我們的社群論壇 與社群展開對話。