次の方法で共有


ユーザー モードのモニター

ユーザー モード モニターを使用すると、"テスト中のプロセス" の実行に関する詳細なコンテキストを取得して、不合格になったテストを調査するための詳しいコンテキストを取得したり、既存のテストの検証精度を高めたりできます。 現在実装されているユーザー モード モニターは基本的な機能を搭載していますが、今後のリリースで、より豊富なカスタマイズと構成が可能になる予定です。

はじめに

ユーザー モード モニター (UMM) は、下位レベルの Windows API を使用して、特定のプロセス (ほんの一例を挙げるとスレッドの開始と停止、モジュールの読み込み、クラッシュ、処理された例外など) から発生したすべての "デバッガー" イベントの通知を受け取ります。 デバッガー イベントが届いたら、UMM コードを通じて、コメントのログ記録、エラーのログ記録 (テストを不合格にするため)、Process Under Test のミニダンプの取得など、いくつかのアクションのいずれかを実行できます。

ユーザー モード モニターを有効にする

特定のテスト ケースで UMM を有効にするには、構成に以下の 2 つの要素を含める必要があります。

  1. テストが "ProcessUnderTest" メタデータ値でマークされること。 これは、UMM がテスト対象のプロセスを識別できるようにするためです。
  2. UMM 機能をオンにするための Te.exe コマンド ラインに "/userModeMonitor" が含まれていること。

UMM コードを使用する場合は、以下のことを考慮する必要があります。

  1. "Process Under Test" という名前が付いたインスタンスが複数存在する場合は、最初に検出されたインスタンスが使用されます。
  2. テストの自動化を実行しているユーザーには、Process Under Test からデバッガー イベントを受信するための十分なアクセス許可が必要です。
  3. UMM コードは、すべてのセットアップ フィクスチャが実行された後で Process Under Test に "アタッチ" され、クリーンアップ フィクスチャが実行される前に "デタッチ" されます。 これにより、テストのセットアップ フィクスチャで Process Under Test を開始して、必要な初期化を実行してテストの準備を行えるようになります。

サポートされているユーザー モード モニターの "アクション"

ユーザー モード モニターには、監視対象のプロセスで特定のデバッガー イベントが発生したときに実行できる一連の "アクション" があります。 現在の実装では、特定のイベントで呼び出されるのは既定のアクションだけです。現時点で、構成のサポートはありません。

アクション 説明
LogComment イベントからのコンテキスト情報を含むコメントをログに追加します。
LogError エラーをログに記録し、現在のテストを不合格にします。
Minidump ミニダンプを書き出してログに保存します。
Ignore 何も実行しません。

サポートされるユーザー モード モニターの "イベント"

ユーザー モード モニターには、先ほどの一覧に掲載されている "アクション" の 1 つを適用できる "イベント" が表示されます。 次の表に、現時点で報告されるイベントと、イベントの受信時に実行される既定のアクションをまとめています。

イベント 既定のアクション (2 回目の既定のアクション)
スレッドの作成 Ignore
スレッドの終了 Ignore
プロセスの作成 Ignore
プロセスの終了 LogError
モジュールの読み込み LogComment
モジュールのアンロード Ignore
システム エラー Ignore
初期ブレークポイント LogError
初期モジュールの読み込み Ignore
デバッグ対象の出力 LogComment
アクセス違反 LogError (LogError)
アサーション エラー LogError (LogError)
アプリケーションのハング LogError (LogError)
中断命令の例外 LogError
中断命令の例外の継続 Ignore
C++ EH の例外 LogError (LogError)
CLR 例外 LogError (LogError)
CLR 通知の例外 LogError (Ignore)
Control-LogError の例外 LogError
Control-LogError の例外の継続 Ignore
Control-C の例外 LogError
Control-C の例外の継続 Ignore
データの不整合 LogError (LogError)
デバッガー コマンドの例外 Ignore
ガード ページ違反 LogError (LogError)
無効な命令 LogError (LogError)
ページ内 I/O エラー LogError (LogError)
整数を 0 で除算 LogError (LogError)
整数オーバーフロー LogError (LogError)
ハンドルが無効です LogError
無効なハンドルの継続 LogError
無効なロック シーケンス LogError (LogError)
無効なシステム呼び出し LogError (LogError)
ポートの切断 LogError (LogError)
サービスのハング LogError (LogError)
単一ステップの例外 LogError
単一ステップの例外の継続 Ignore
スタックのバッファー オーバーフロー LogError (LogError)
スタック オーバーフロー LogError (LogError)
検証ツールの停止 LogError (LogError)
Visual C++ の例外 Ignore (Ignore)
デバッガーのスリープ解除 LogError (LogError)
WOW64 ブレークポイント LogError (Ignore)
WOW64 単一ステップの例外 LogError (Ignore)
その他の例外 LogError (LogError)

UMM の機能の使い方を紹介するために、"MSPaint" を自動化するテストの (少し強引な) 例を見てみましょう。

namespace UserModeMonitorExample
{
    using System;
    using System.Diagnostics;
    using System.Threading;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using WEX.Logging.Interop;
    using WEX.TestExecution;

    [TestClass]
    public class BasicExample
    {
        [TestInitialize]
        public void TestInitialize()
        {
            Process[] runningPaintInstances = Process.GetProcessesByName("mspaint.exe");

            Verify.IsTrue(runningPaintInstances.Length == 0, "There are no running instances of mspaint.exe");

            this.mspaintUnderTest = Process.Start("mspaint.exe");
        }

        [TestCleanup]
        public void TestCleanup()
        {
            // Close the 'mspaint under test' - if it's already gone, this will throw, but that's no big deal.
            this.mspaintUnderTest.CloseMainWindow();
        }

        [TestMethod]
        [TestProperty("ProcessUnderTest", "mspaint.exe")]
        [TestProperty("Description", "Shows how a test can be failed if the UI is closed from underneath the test.")]
        public void SimpleInteraction()
        {
            Log.Comment("If the 'user mode monitor' is enabled and mspaint.exe is closed,");
            Log.Comment("then this test will be failed.");
            Log.Comment("Sleeping for 5 seconds");

            Thread.Sleep(TimeSpan.FromSeconds(5));
        }

        private Process mspaintUnderTest;
    }
}

テストの構造を大まかに分解すると、以下のようになります。

  • "SimpleInteraction" テストは、UI ベースのアプリケーション (この場合は "MSPaint.exe") とやり取りするテストを表します。 これが "mspaint.exe" プロセスのテストであることをコール アウトするために、"ProcessUnderTest" メタデータが適用されていることに注目してください。
  • テストには、既存のインスタンスが実行されていないことを確認し、テストするインスタンスを 1 つ起動するためのセットアップ フィクスチャがあります。
  • テストには、セットアップ フィクスチャで起動されたインスタンスを閉じるためのクリーンアップ フィクスチャもあります。

"テスト" はとても単純です。考えられる結果を以下に検討してみましょう。

  1. テストが問題なく実行される。 これが最良の結果です。
  2. UMM が有効になっておらず、ユーザーが実行中に MSPaint インスタンスを閉じる。 この場合、テストは合格になりますが、クリーンアップには失敗して "InvalidOperationException" が返されます。
  3. UMM が有効になっていて、ユーザーが実行中に MSPaint インスタンスを閉じる。 この場合、UMM コードによって、プロセスが終了してテストが不合格になったことを示すエラーがログに記録されます。 クリーンアップは、(2) の場合と同じく失敗します。

UMM が有効になっていると、誤った動作が直ちに報告され、テスト結果に直接影響します。 エラーが速やかに報告され、テスト不合格のデバッグや理解に役立つ追加のコンテキストが提供されるので、テストのパターンとしてはこれがはるかに優れています。