用户模式监视器

用户模式监视器允许测试获取有关“受测进程”执行的更多上下文,以便获取更多上下文来调查测试失败,或从现有测试中启用更好的验证。 当前的用户模式监视器实现提供基本实现,后续版本中会提供更多自定义和配置。

简介

用户模式监视器 (UMM) 使用低级别 Windows API 收到源自给定进程的所有“调试器”事件的通知 - 线程启动和停止、模块加载、崩溃和处理异常等。 收到调试器事件后,UMM 代码可以执行多项操作之一,包括记录注释、记录错误 (以使测试) 失败,甚至采取受测进程的小型转储。

启用用户模式监视器

若要为给定测试用例启用 UMM,需要提供两个配置:

  1. 必须使用“ProcessUnderTest”元数据值标记测试。 这允许 UMM 标识正在测试的进程。
  2. Te.exe命令行应包含“/userModeMonitor”以打开 UMM 功能。

使用 UMM 代码时,应考虑以下几点:

  1. 如果有多个命名的受测进程的实例正在运行,则将使用首先发现的实例。
  2. 执行测试自动化的用户必须具有足够的权限才能从受测进程接收调试器事件。
  3. 在执行所有安装装置后,UMM 代码将“附加”到受测进程,并在执行清理装置之前“分离”。 这允许测试的设置固定例程启动受测进程,并执行任何必要的初始化来准备测试。

支持的用户模式监视器“操作”

用户模式监视器具有一组“操作”,当受监视的进程中发生给定的调试器事件时,它可以采取这些“操作”。 在当前实现中,给定事件将仅调用其默认操作;目前没有配置支持。

操作 说明
LogComment 将注释添加到日志,其中包含来自 事件的上下文信息。
LogError 将错误记录到日志中,该错误将使当前测试失败。
小型转储 写出一个小型转储并将其保存到日志中。
忽略 不执行任何操作。

支持的用户模式监视器“事件”

用户模式监视器显示“事件”,可以应用上面列出的“操作”之一。 下表显示了报告事件的当前列表,以及接收事件时将执行的默认操作。

事件 默认操作 (第二次机会默认操作)
创建线程 忽略
退出线程 忽略
创建流程 忽略
退出进程 LogError
加载模块 LogComment
卸载模块 忽略
系统错误 忽略
初始断点 LogError
初始模块加载 忽略
调试对象输出 LogComment
访问冲突 LogError (LogError)
断言失败 LogError (LogError)
应用程序挂起 LogError (LogError)
中断指令异常 LogError
中断指令异常继续 忽略
C++ EH 异常 LogError (LogError)
CLR 异常 LogError (LogError)
CLR 通知异常 LogError (Ignore)
Control-LogError异常 LogError
Control-LogError异常继续 忽略
Control-C 异常 LogError
Control-C 异常继续 忽略
数据未对齐 LogError (LogError)
调试器命令异常 忽略
保护页冲突 LogError (LogError)
非法指令 LogError (LogError)
页内 I/O 错误 LogError (LogError)
整数除以零 LogError (LogError)
整数溢出 LogError (LogError)
无效句柄 LogError
无效句柄继续 LogError
无效的锁序列 LogError (LogError)
系统调用无效 LogError (LogError)
端口已断开连接 LogError (LogError)
服务挂起 LogError (LogError)
单步异常 LogError
单步异常继续 忽略
堆栈缓冲区溢出 LogError (LogError)
堆栈溢出 LogError (LogError)
验证程序停止 LogError (LogError)
Visual C++ 异常 忽略 (忽略)
唤醒调试器 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”。 请注意,已应用“ProcessUnderTest”元数据来指示此测试正在测试“mspaint.exe”进程。
  • 测试具有一个安装装置,可确保没有运行预先存在的实例,并启动单个实例进行测试。
  • 测试还有一个清理固定装置,用于关闭在设置固定装置中启动的实例。

“测试”非常直接,让我们看看可能的结果:

  1. 测试在没有问题的情况下运行。 这是最佳可能的结果。
  2. 如果不启用 UMM,用户在执行期间会关闭 MSPaint 实例。 在这种情况下,测试将通过,但清理将失败并显示“InvalidOperationException”。
  3. 启用 UMM 后,用户在执行期间关闭 MSPaint 实例。 在这种情况下,UMM 代码将记录一个错误,显示进程关闭未通过测试。 清理失败,因为 (2) 。

启用 UMM 后,将立即报告错误行为,并直接影响测试结果。 这是一种更好的测试模式,因为会尽早报告错误,并提供额外的上下文来帮助调试或了解测试失败。