次の方法で共有


MSTest ライフサイクル

MSTest には、テスト クラスとテスト メソッドの明確に定義されたライフサイクルが用意されており、テスト実行のさまざまな段階でセットアップ操作と破棄操作を実行できます。 ライフサイクルを理解することは、効率的なテストを記述し、一般的な落とし穴を回避するのに役立ちます。

ライフサイクルの概要

ライフサイクルは、最高レベル (アセンブリ) から最下位レベル (テスト メソッド) に実行される 4 つのステージにグループ化されます。

  1. アセンブリ レベル: テスト アセンブリの読み込みとアンロード時に 1 回実行されます
  2. クラス レベル: テスト クラスごとに 1 回実行
  3. グローバル テスト レベル: アセンブリ内のすべてのテスト メソッドの前後に実行されます
  4. テスト レベル: 各テスト メソッドに対して実行されます (パラメーター化されたテストの各データ行を含む)

アセンブリ レベルのライフサイクル

アセンブリ ライフサイクル メソッドは、テスト アセンブリの読み込みとアンロード時に 1 回実行されます。 データベースの初期化やサービスの起動など、コストの高い 1 回限りのセットアップに使用します。

および

[TestClass]
public class AssemblyLifecycleExample
{
    private static IHost? _host;

    [AssemblyInitialize]
    public static async Task AssemblyInit(TestContext context)
    {
        // Runs once before any tests in the assembly
        _host = await StartTestServerAsync();
        context.WriteLine("Test server started");
    }

    [AssemblyCleanup]
    public static async Task AssemblyCleanup(TestContext context)
    {
        // Runs once after all tests complete
        // TestContext parameter available in MSTest 3.8+
        if (_host != null)
        {
            await _host.StopAsync();
        }
    }

    private static Task<IHost> StartTestServerAsync()
    {
        // Server initialization
        return Task.FromResult<IHost>(null!);
    }
}

Requirements

  • メソッドは〘
  • 戻り値の型: 、 、または (MSTest v3.3 以降)
  • には、1 つの パラメーターが必要です
  • 0 個のパラメーターまたは 1 つの パラメーターを受け取ります (MSTest 3.8 以降)
  • アセンブリごとに許可される各属性の 1 つだけ
  • でマークされたクラスに存在する必要があります

ヒント

関連するアナライザー:

  • MSTEST0012 - 署名 検証します。
  • MSTEST0013 - 署名 検証します。

クラス レベルのライフサイクル

クラス ライフサイクル メソッドは、テスト クラスごとに、そのクラスのすべてのテスト メソッドの前後に 1 回実行されます。 これらは、クラス内のテスト間で共有されるセットアップに使用します。

および

[TestClass]
public class ClassLifecycleExample
{
    private static HttpClient? _client;

    [ClassInitialize]
    public static void ClassInit(TestContext context)
    {
        // Runs once before any tests in this class
        _client = new HttpClient
        {
            BaseAddress = new Uri("https://api.example.com")
        };
    }

    [ClassCleanup]
    public static void ClassCleanup()
    {
        // Runs after all tests in this class complete
        _client?.Dispose();
    }

    [TestMethod]
    public async Task GetUsers_ReturnsSuccess()
    {
        HttpResponseMessage response = await _client!.GetAsync("/users");
        Assert.IsTrue(response.IsSuccessStatusCode);
    }
}

Requirements

  • メソッドは〘
  • 戻り値の型: 、 、または (MSTest v3.3 以降)
  • には、1 つの パラメーターが必要です
  • 0 個のパラメーターまたは 1 つの パラメーターを受け取ります (MSTest 3.8 以降)
  • クラスごとに許可される各属性の 1 つだけ

継承の振る舞い

を使って、派生クラスがを実行するかどうかを制御します。

[TestClass]
public class BaseTestClass
{
    [ClassInitialize(InheritanceBehavior.BeforeEachDerivedClass)]
    public static void BaseClassInit(TestContext context)
    {
        // Runs before each derived class's tests
    }
}

[TestClass]
public class DerivedTestClass : BaseTestClass
{
    [TestMethod]
    public void DerivedTest()
    {
        // BaseClassInit runs before this class's tests
    }
}
InheritanceBehavior Description
(既定値) 宣言するクラスに対してのみ実行を初期化する
BeforeEachDerivedClass 各派生クラスの前に実行を初期化する

ヒント

関連するアナライザー:

  • MSTEST0010 - 署名 検証します。
  • MSTEST0011 - 署名 検証します。
  • MSTEST0034 - の使用をお勧めします。

グローバルテストレベルライフサイクル

グローバル テスト ライフサイクル属性は、MSTest 3.10.0 で導入されました。

グローバル テスト ライフサイクル メソッドは、各テスト クラスにコードを追加する必要なく、アセンブリ全体 のすべての テスト メソッドの前後に実行されます。

および

[TestClass]
public class GlobalTestLifecycleExample
{
    [GlobalTestInitialize]
    public static void GlobalTestInit(TestContext context)
    {
        // Runs before every test method in the assembly
        context.WriteLine($"Starting test: {context.TestName}");
    }

    [GlobalTestCleanup]
    public static void GlobalTestCleanup(TestContext context)
    {
        // Runs after every test method in the assembly
        context.WriteLine($"Finished test: {context.TestName}");
    }
}

Requirements

  • メソッドは〘
  • 戻り値の型: 、 、または
  • パラメーターは正確に 1 つである必要があります。
  • でマークされたクラスに存在する必要があります
  • これらの属性を持つ複数のメソッドがアセンブリ全体で許可される

複数の または メソッドが存在する場合、実行順序は保証されません。 は、メソッドではサポートされていません。

ヒント

関連アナライザー: MSTEST0050 - グローバル テスト フィクスチャ メソッドを検証します。

試験段階のライフサイクル

テスト レベルのライフサイクルは、すべてのテスト メソッドに対して実行されます。 パラメーター化されたテストの場合、ライフサイクルはデータ行ごとに実行されます。

セットアップ フェーズ

テストごとのセットアップには、 またはコンストラクターを使用します。

[TestClass]
public class TestLevelSetupExample
{
    private Calculator? _calculator;

    public TestLevelSetupExample()
    {
        // Constructor runs before TestInitialize
        // Use for simple synchronous initialization
    }

    [TestInitialize]
    public async Task TestInit()
    {
        // Runs before each test method
        // Supports async, attributes like Timeout
        _calculator = new Calculator();
        await _calculator.InitializeAsync();
    }

    [TestMethod]
    public void Add_TwoNumbers_ReturnsSum()
    {
        int result = _calculator!.Add(2, 3);
        Assert.AreEqual(5, result);
    }
}

コンストラクターと TestInitialize:

特徴 コンストラクター TestInitialize
非同期サポート いいえ イエス
タイムアウトのサポート いいえ はい ( 属性を使用)
実行順序 First コンストラクタ処理後
継承 次に派生した Base 次に派生した Base
例外の動作 クリーンアップと Dispose が実行されない (インスタンスが存在しない) クリーンアップとDisposeはまだ実行中です。

ヒント

どの方法を使用する必要がありますか? コンストラクターは、不変性を強制し、テスト クラスの推論を容易にする フィールドを使用できるため、一般的に推奨されます。 非同期初期化またはタイムアウトのサポートが必要な場合は、 を使用します。

また、両方の方法を組み合わせることもできます。 フィールドの単純な同期初期化にはコンストラクターを使用し、それらのフィールドに依存する追加の非同期セットアップには を使用します。

必要に応じて、コード アナライザーを有効にして、一貫したアプローチを適用できます。

  • MSTEST0019 - コンストラクターよりも TestInitialize メソッドを優先する
  • MSTEST0020 - TestInitialize メソッドよりもコンストラクターを優先する

実行フェーズ

テスト メソッドは、セットアップが完了した後に実行されます。 テスト メソッドの場合、MSTest は返されたまたはを待機します。

Warnung

非同期テスト メソッドには、既定では はありません。 これは、UI スレッドで実行される UWP および WinUI の テストには適用されません。

クリーンアップ フェーズ

テストごとのクリーンアップには、 または を使用します。

[TestClass]
public class TestLevelCleanupExample
{
    private HttpClient? _client;

    [TestInitialize]
    public void TestInit()
    {
        _client = new HttpClient();
    }

    [TestCleanup]
    public void TestCleanup()
    {
        if (_client != null)
        {
            _client.Dispose();
        }
    }

    [TestMethod]
    public async Task GetData_ReturnsSuccess()
    {
        HttpResponseMessage response = await _client!.GetAsync("https://example.com");
        Assert.IsTrue(response.IsSuccessStatusCode);
    }
}

クリーンアップの実行順序 (基本に派生):

  1. (派生クラス)
  2. (基底クラス)
  3. (実装されている場合)
  4. (実装されている場合)

ヒント

必要に応じて、コード アナライザーを有効にして、一貫したクリーンアップ アプローチを適用できます。

  • MSTEST0021 - TestCleanup メソッドよりも Dispose を優先する
  • MSTEST0022 - Dispose メソッドよりも TestCleanup を優先する

.NET コード分析ルールなど、MSTest 以外のアナライザーが有効になっている場合は、CA1001テスト クラスが破棄可能なリソースを所有する場合に dispose パターンを実装することを提案している可能性があります。 これは予期される動作であり、アナライザーのガイダンスに従う必要があります。

テスト段階の順序を完了する

  1. テスト クラス (コンストラクター) のインスタンスを作成する
  2. プロパティ 設定する (存在する場合)
  3. メソッドを実行する
  4. メソッドを基底から派生クラスまで実行する
  5. テスト メソッドの実行
  6. 結果で を更新する ( プロパティなど)
  7. メソッドを実行する (派生クラスから基本クラスへ)
  8. メソッドを実行する
  9. を実行する (実装されている場合)
  10. を実行する (実装されている場合)

ヒント

関連するアナライザー:

  • MSTEST0008 - 署名 検証します。
  • MSTEST0009 - 署名 検証します。
  • MSTEST0063 - テスト クラスコンストラクターを検証します。

ベスト プラクティス

  1. 適切なスコープを使用する: 冗長な作業を回避するために、セットアップを最も高いレベルに配置します。

  2. セットアップを高速に保つ: 実行時間の長いセットアップは、すべてのテストに影響します。 コストの高いリソースについては、遅延初期化を検討してください。

  3. 適切にクリーンアップする: 常にリソースをクリーンアップして、テストの干渉とメモリ リークを防ぎます。

  4. 非同期を正しく処理する: 戻り値の型を使用し、ではなく非同期ライフサイクル メソッドにしてください。

  5. テストの分離を検討する: 各テストは独立している必要があります。 テスト間で変更可能な状態を共有しないようにします。

  6. GlobalTest を慎重に使用する: グローバル ライフサイクル メソッドは、すべてのテストに対して実行されるため、軽量に保ちます。

こちらも参照ください

  • MSTest でテストを記述する
  • テストの実行と制御
  • TestContext クラス