りおんクロニクル


SQLite × InMemory テスト戦略|高速・副作用ゼロの実務ガイド【2026年版】

Home【2026年版】C# / .NET入門と実践ガイド|基礎・業務アプリ開発・SQLite連携まで体系的に解説

業務アプリの品質を高めるには、 DBを含めたテスト(Integration Test)が欠かせません。 しかし、実ファイルのSQLiteを使うと「遅い・壊れる・後片付けが面倒」という問題が出ます。

そこで最強なのが、SQLiteのInMemoryモード。 メモリ上にDBを作るため、 高速・副作用ゼロ・テストごとに初期化可能というメリットがあります。

この記事でわかること
・SQLite InMemoryの基本
・テストDBの初期化方法
・Repository + Unit of Workとの組み合わせ
・Dapper / EF Core 両対応の実装例
・業務アプリ向けテスト戦略

1. SQLite InMemoryとは?

SQLiteには、ファイルを作らずメモリ上にDBを作るモードがあります。

■ 接続文字列

Data Source=:memory:;Cache=Shared

Cache=Shared が重要で、 複数の接続から同じInMemory DBにアクセスできます。

2. InMemory DBの特徴

3. InMemory DBの作成(C#)

using Microsoft.Data.Sqlite;

var cs = "Data Source=:memory:;Cache=Shared";
var con = new SqliteConnection(cs);
con.Open();

// テーブル作成
var cmd = con.CreateCommand();
cmd.CommandText = @"
CREATE TABLE Users (
    Id INTEGER PRIMARY KEY AUTOINCREMENT,
    Name TEXT NOT NULL,
    Age INTEGER
);";
cmd.ExecuteNonQuery();

ポイントは接続を閉じないこと。 InMemory DBは「最後の接続が閉じられた瞬間に消える」ためです。

4. テスト用DBを初期化する関数

public static SqliteConnection CreateInMemoryDb()
{
    var cs = "Data Source=:memory:;Cache=Shared";
    var con = new SqliteConnection(cs);
    con.Open();

    using var cmd = con.CreateCommand();
    cmd.CommandText = @"
        CREATE TABLE Users (
            Id INTEGER PRIMARY KEY AUTOINCREMENT,
            Name TEXT NOT NULL,
            Age INTEGER
        );
    ";
    cmd.ExecuteNonQuery();

    return con; // 接続を保持したまま返す
}

5. Repository + Unit of Work と組み合わせる

InMemory DBは、Repository/UoWと組み合わせると最強になります。

■ テスト用Unit of Work

public class TestUnitOfWork : IUnitOfWork
{
    private readonly SqliteConnection _con;
    private readonly SqliteTransaction _tran;

    public IUserRepository Users { get; }

    public TestUnitOfWork(SqliteConnection con)
    {
        _con = con;
        _tran = _con.BeginTransaction();

        Users = new SqliteUserRepository(_con, _tran);
    }

    public Task CommitAsync() => _tran.CommitAsync();
    public Task RollbackAsync() => _tran.RollbackAsync();

    public ValueTask DisposeAsync()
    {
        _tran.Dispose();
        return ValueTask.CompletedTask;
    }
}

6. テストコード例(xUnit)

public class UserRepositoryTests
{
    [Fact]
    public async Task AddUser_ShouldInsertCorrectly()
    {
        var con = TestDb.CreateInMemoryDb();

        await using var uow = new TestUnitOfWork(con);

        var user = new User { Name = "Taro", Age = 20 };
        await uow.Users.AddAsync(user);
        await uow.CommitAsync();

        var result = await uow.Users.GetByIdAsync(1);

        Assert.Equal("Taro", result.Name);
    }
}

テストごとにDBが初期化されるため、 テストの独立性が高く、再現性も完璧です。

7. EF CoreでInMemory SQLiteを使う場合

EF Coreには「InMemory Provider」がありますが、 SQLiteの動作と異なるため非推奨です。

代わりに、UseSqlite + InMemory接続を使うのが正解。

var con = new SqliteConnection("Data Source=:memory:");
con.Open();

var options = new DbContextOptionsBuilder<AppDbContext>()
    .UseSqlite(con)
    .Options;

using var db = new AppDbContext(options);
db.Database.EnsureCreated();

8. テストデータ投入(Seed)

テスト開始時にデータを投入する関数を用意しておくと便利。

public static void SeedUsers(SqliteConnection con)
{
    var sql = "INSERT INTO Users (Name, Age) VALUES (@name, @age)";
    con.Execute(sql, new { name = "Taro", age = 20 });
    con.Execute(sql, new { name = "Hanako", age = 25 });
}

9. 業務アプリ向けベストプラクティス

まとめ:InMemory SQLiteは“高速・安全・再現性100%”の最強テスト環境

「実DBに近い動作で高速にテストしたい」 そんなニーズに最も応えるのが InMemory SQLite です。 この記事をベースに、あなたのアプリに最適なテスト基盤を構築してみてください。

前のページ  次のページ