2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

TestContainer for .Netを使い、まっさらなDBでUnitTestを行う

Last updated at Posted at 2022-11-18

目的

Usecaseに対して初期化したDBをTestContainer for .Netで用意しUnitTestをする

環境

  • .Net6
  • Docker
  • docker-compose.yml
  • EntityFrameworkCore
  • Postgres
  • TestContainer for .Net
  • xunit
    上記を利用します

TestContainer for .Net

アプリ上でContainerの起動&停止を行ってくれます。今回はPostgresのコンテナの起動&停止を行います。
TestContainerはContainerのPullは行ってくれないので、事前にPullしておく必要があります。

docker pull testcontainers/ryuk:0.3.4

Postgres

TestContainer経由でPostgresを立ち上げますが、こちらもPullしてくれないので、事前にPullしましょう

docker pull postgres:14.4

成果物

リポジトリ
にコードがあるので参照してください。

このコードは

  1. UnitTest開始
  2. TestContainerでPostgresから作成(テストクラス毎)
  3. テーブル作成
  4. 初期データを投入
  5. テスト
  6. DB削除
    です

テーブルと初期データ

Postgres起動時にinit.sqlを実行します。init.sqlはpostgresql\initにあり
/docker-entrypoint-initdb.dにマウントすることによりユーザ作成、テーブル作成、初期データ投入します

スキーマや初期データに変更がある場合はinit.sqlを書き換えてください。

テストクラス

public class UserUsecaseTest : IClassFixture<TestBase>

TestBaseというクラスにTestContainerでPostgres起動するロジックを記載しています
UserUsecaseTestはIClassFixtureを継承しており、クラスの初期化でTestBaseを呼ぶことになります。

public class TestBase : IDisposable
{
    public TestBase()
    {
        //EntityFrameworkCoreの設定、TestContainerで立ち上げたPostgresに接続
        _services.AddDbContext<SampleDbContext>(Options =>
           {
               Options.UseNpgsql(UnitTestConnectionString);
           });

        //UnitTestで使うサービスをDIに登録
        _services.AddScoped<IUserRepository, UserRepository>();
        _services.AddScoped<IUserUsecase, UserUsecase>();

        ServiceProvider = _services.BuildServiceProvider();
        //TestContainer起動
        Initialize();
    }
    public void Dispose()
    {
        //Postgresの停止&削除
        Task.Run(_postgresqlContainer!.DisposeAsync).GetAwaiter().GetResult();
    }

}

TestBaseのコンストラクタでDIの設定、TestContainer起動
Disposeで後始末を行っています。

詳細はコードを参照してください

[assembly: CollectionBehavior(DisableTestParallelization = true)]

でテストは直列で行うようにしています。これは並列にするとDBが複数立ち上がりリソース圧迫を防ぐ目的です。

おまけ

UT/docker-compose.ymlを置いているので

docker compose up

でUnitTestで使用するDBと同じものを違うContainerで立ち上げることができます。
デバッグや開発ではこちらを使い、スキーマや初期データがそろったら、init.sqlを変更しUnitTestを行うというフローが出来ます
その場合
Database名:test
ユーザ:user
パスワード:pass
docker-compose.ymlに記載しているので適宜変更してください

感想

DBをテストクラス毎に起動&停止を行うので試験に時間はかかりますが、本番環境とは違うDB、例えばInMemoryやSQLiteなどを利用することなく、本番と同環境でUnitTestが出来ることに意義があると思っています。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?