截至目前,我的 EF Core 範例都是用 dotnet ef migrations create 產生建立(或升級) Schema 所需程式,再透過 dotnet ef database update 或 DbContext.Database.Migrate() 套用 Migration 建立或修改資料表。

但在雛型驗證階段或跑自動測試,有個更省事的做法 - DbContext.Database.EnsureCreated(),其執行規則為:

  1. 若資料庫存在且有任何資料表,不執行動作,傳回 false
  2. 若資料庫存在且沒有任何資料表,則使用 EF Model 建立資料表
  3. 若資料庫不存在,則先建立資料庫再依 EF Model 建立資料表

EnsureCreated() 的缺點是適用空白資料庫全新建立,不像 Migration 可依資料庫現況增減資料表、欄位、索引,再套用現存資料庫將 Schema 更新到最新狀態。用 EnsureCreated() 建立的資料表,之後也無法再用 Migration 套用更新。

實驗驗證或自動測試時,資料庫通常測完即抛,沒有後續更新問題,便適合使用 EnsureCreated(),省去建立 Migration 程序。

以昨天的 StaticFileDbContext 為實例,我想對它做自動測試,試試資料表寫入是否正常,可以這樣做:

using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.IO;
using Microsoft.EntityFrameworkCore;
using Microsoft.Data.Sqlite;
using Drk.AspNetCore.FileProviders;
using System.Linq;
using System.Text;
namespace test_dbctx;

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        var dbPath = "test.sqlite";
		// 清除之前殘留資料庫檔案
        if (File.Exists(dbPath)) File.Delete(dbPath);
        var opt = new DbContextOptionsBuilder<StaticFileDbContext>()
            .UseSqlite($"data source={dbPath}").Options;
        var ctx= new StaticFileDbContext(opt);
		// 建立資料表
        ctx.Database.EnsureCreated();
        var resp = new StaticFileDbRepository(ctx);
        Assert.AreEqual(ctx.StaticFileIndices.Count(), 0);
        var userId = "jeffrey";
        var clientIp = "::1";
        resp.UpdateFile("/test.txt", Encoding.UTF8.GetBytes("ABC"), userId, clientIp);
        Assert.AreEqual(ctx.StaticFileIndices.Count(), 2);
        var testTxt = Encoding.UTF8.GetString(resp.ReadFile("/test.txt").Content);
        Assert.AreEqual(testTxt, "ABC");
    }
}

使用 .NET CLI 一鏡到底之測試程序如下:

dotnet new mstest -o test-dbctx
cd test-dbctx
dotnet add package Drk.AspNetCore.FileProviders
rem 將 UnitTest1.cs 換成上面的程式碼
dotnet test

測試成功!

不過,由於 EnsureCreated() 的偵測條件是資料庫不存在任何資料表,若有多個 DbContext 共用資料庫,只有第一個執行 EnsureCreated() 的 DbContext 會建立資料表,第二個 DbContext EnsureCreated() 時會因已存在第一個 DbContext 的資料表而不執行動作(如下圖),此時需依賴 Migration 才能完整建立。單元測試多半聚焦單一 DbContext,倒是可安心使用。

Introduce to EF Core EnsureCreated(), including pros and limitations.


Comments

# by Cash

E2E 測試的時候很好用 !!

Post a comment