xUnit.NET の パラレルテスト と SQL Server (Local DB) で bacpac から import のメモ

上手くいくかは未検証!

データは、if exists drop database + import bacpac で考える。
※楽だから
Local DB 前提で書いたけど、Local DB じゃなくても問題無さそう。

テスト側ではトランザクション制御出来ない前提。
Web App とかで HTTP 跨ぐようなイメージ。
メソッドのテストなら、テストで呼び出すときに、
TransactionScope で囲って Complete 呼ばないとかでトランザクション 制御出来るケースが多そう。

  • テストの種類
    • DB 使わない
    • DB 使う : read only (テストデータ投入もしない。bacpac だけで完結)
    • DB 使う : read write (bacpac + 個別のテストデータ or テスト中に書き換え)

xUnit.NET は何もしてないと全テストパラレルで動くはず。

  • DB 使わない (パラで問題なし)
  • DB 使う (read only) (以下の内容に気を付ければパラで問題なし)
    • bacpac の import を テスト全体で1回だけ起こるようにする。
      • bacpac の import 時間削減 + 他テスト中に drop database / import bacpac が起きないように
      • C#9(.NET 5) の module initializer で良さげ
  • DB 使う (read write) (パラでは問題あり)
    • write があるので、「他のテストと同じ database を参照している」とタイミングで問題が出そう。
      • read write がある テスト は、他のテストと別の database (database 名 / 接続文字列 Initial Catalog)に変えて、bacpac を import して動かしたら他のテストとパラでも問題無い。
        • テスト対象のアプリは、HostBuilder なりなんなりで、接続文字列を差し替え出来る前提
        • 同じ database 名で動作するテストは パラ だと困る。
          • XUnit.Collection でグルーピング。Collection 名を database 名したら良さげ。

まとめ

  • module initializer で read only で使う共通の DB を import する
  • write があるテストは、それぞれ XUnit.Collection + Database 名を変更して、別の Database として import して、Collection 単位でパラレルに動く

参考資料

NuGet Gallery | xunit 2.4.1
NuGet Gallery | Microsoft.SqlServer.DacFx 150.5164.1
Running Tests in Parallel > xUnit.net
Shared Context between Tests > xUnit.net
Module initializers - C# 9.0 specification proposals | Microsoft Docs
DROP DATABASE (Transact-SQL) - SQL Server | Microsoft Docs
ASP.NET Core MVC アプリのテスト | Microsoft Docs
DACExtensions/SqlTestDb.cs at 6ed437b23fdc0fb959394afd7d5aba99f64022f8 · microsoft/DACExtensions · GitHub