Freigeben über


Benutzermodusmonitor

Der Benutzermodusmonitor ermöglicht Es Tests, mehr Kontext zur Ausführung des zu testenden Prozesses abzurufen, um mehr Kontext für die Untersuchung von Testfehlern zu erhalten oder eine bessere Überprüfung aus vorhandenen Tests zu ermöglichen. Die aktuelle Implementierung des Benutzermodusmonitors bietet eine einfache Implementierung mit weiteren Anpassungen und Konfigurationen, die in den nachfolgenden Versionen verfügbar sind.

Einführung

Der Benutzermodusmonitor (UMM) verwendet Windows-APIs auf niedriger Ebene, um über alle Debuggerereignisse benachrichtigt zu werden, die von einem bestimmten Prozess stammen– Threadstart und -stopp, Modulladevorgänge, Abstürze und behandelte Ausnahmen, um nur einige zu nennen. Beim Empfangen eines Debuggerereignisses kann der UMM-Code eine von mehreren Aktionen ausführen, z. B. das Protokollieren von Kommentaren, das Protokollieren von Fehlern (um einen Test zu scheitern) oder sogar einen Minidump des Testprozesses auszuführen.

Aktivieren des Benutzermodusmonitors

Um UMM für einen bestimmten Testfall zu aktivieren, müssen Sie zwei Konfigurationsschritte bereitstellen:

  1. Der Test muss mit dem Metadatenwert "ProcessUnderTest" markiert werden. Dadurch kann UMM den prozess identifizieren, der getestet wird.
  2. Die Te.exe Befehlszeile sollte "/userModeMonitor" enthalten, um die UMM-Funktionalität zu aktivieren.

Die folgenden Punkte sollten bei der Verwendung des UMM-Codes berücksichtigt werden:

  1. Wenn mehrere Instanzen des namens Process Under Test ausgeführt werden, wird die zuerst ermittelte instance verwendet.
  2. Der Benutzer, der die Testautomatisierung ausführt, muss über ausreichende Berechtigungen verfügen, um Debuggerereignisse aus dem Testprozess zu empfangen.
  3. Der UMM-Code wird an den Testprozess "angefügt", nachdem alle Setupvorrichtungen ausgeführt wurden, und "trennen", bevor Bereinigungsvorrichtungen ausgeführt werden. Dadurch können die Einrichtungsvorrichtungen eines Tests den Testprozess starten und alle erforderlichen Initialisierungen durchführen, um den Test vorzubereiten.

Unterstützte Benutzermodusüberwachung "Aktionen"

Der Benutzermodusmonitor verfügt über eine Reihe von "Aktionen", die er ausführen kann, wenn ein bestimmtes Debuggerereignis im überwachten Prozess auftritt. In der aktuellen Implementierung ruft ein bestimmtes Ereignis nur die Standardaktion auf. Es gibt derzeit keine Konfigurationsunterstützung.

Action BESCHREIBUNG
LogComment Fügt dem Protokoll einen Kommentar mit kontextbezogenen Informationen aus dem Ereignis hinzu.
LogError Protokolliert einen Fehler im Protokoll, der beim aktuellen Test fehlschlägt.
Minidump Schreibt einen Minidump aus und speichert ihn im Protokoll.
Ignorieren Führt keine Aktion aus.

Unterstützte Benutzermodusüberwachung "Ereignisse"

Der Benutzermodusmonitor zeigt "Ereignisse" an, die eine der oben aufgeführten "Aktionen" anwenden können. Die folgende Tabelle zeigt die aktuelle Liste der gemeldeten Ereignisse zusammen mit der Standardaktion, die ausgeführt wird, wenn das Ereignis empfangen wird.

Ereignis Standardaktion (Standardaktion für die zweite Chance)
Erstellen eines Threads Ignorieren
Thread beenden Ignorieren
Erstellen eines Prozesses Ignorieren
Beenden des Prozesses LogError
Laden des Moduls LogComment
Entladen des Moduls Ignorieren
Systemfehler Ignorieren
Anfänglicher Haltepunkt LogError
Anfängliches Laden des Moduls Ignorieren
Debuggee-Ausgabe LogComment
Zugriffsverletzung LogError (LogError)
Assertionsfehler LogError (LogError)
Anwendungshänger LogError (LogError)
Ausnahme von Unterbrechungsanweisungen LogError
Unterbrechungsanweisungs-Ausnahme fortsetzen Ignorieren
C++-EH-Ausnahme LogError (LogError)
CLR-Ausnahme LogError (LogError)
CLR-Benachrichtigungs-Ausnahme LogError (Ignore)
Control-LogError Ausnahme LogError
Control-LogError Ausnahme wird fortgesetzt. Ignorieren
Control-C-Ausnahme LogError
Control-C-Ausnahme fortsetzen Ignorieren
Falsch ausgerichtete Daten LogError (LogError)
Debuggerbefehls-Ausnahme Ignorieren
Schutzseitenverletzung LogError (LogError)
Ungültige Anweisung LogError (LogError)
In-Page-E/A-Fehler LogError (LogError)
Ganze Zahl dividieren durch Null LogError (LogError)
Ganzzahliger Überlauf LogError (LogError)
Ungültiges Handle LogError
Ungültiges Handle continue LogError
Ungültige Sperrsequenz LogError (LogError)
Ungültiger Systemaufruf LogError (LogError)
Port getrennt LogError (LogError)
Dienst wird nicht reagiert LogError (LogError)
Einzelschritt-Ausnahme LogError
Einzelschritt-Ausnahme fortsetzen Ignorieren
Stack buffer overflow (Stapelpufferüberlauf) LogError (LogError)
Stapelüberlauf LogError (LogError)
Prüfer beenden LogError (LogError)
Visual C++-Ausnahme Ignorieren (Ignorieren)
Aktivierungsdebugger LogError (LogError)
WOW64-Haltepunkt LogError (Ignore)
WOW64-Ausnahme in einem einzelnen Schritt LogError (Ignore)
Andere Ausnahme LogError (LogError)

Beispiel

Um die Verwendung der UMM-Funktionalität zu veranschaulichen, sehen wir uns ein (leicht erfundenes) Beispiel für einen Test an, der "MSPaint" automatisiert:

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;
    }
}

Im Folgenden finden Sie eine kurze Aufschlüsselung der Struktur des Tests:

  • Der "SimpleInteraction"-Test stellt einen Test dar, der mit einer benutzeroberflächenbasierten Anwendung interagiert – in diesem Fall ist es "MSPaint.exe". Beachten Sie, dass die "ProcessUnderTest"-Metadaten angewendet wurden, um darauf hinzuweisen, dass dieser Test den "mspaint.exe"-Prozess testet.
  • Der Test verfügt über eine Setupeinrichtung, die sicherstellt, dass keine bereits vorhandenen Instanzen ausgeführt werden, und startet eine einzelne instance, die getestet werden soll.
  • Der Test verfügt auch über eine Bereinigungsvorrichtung, die die instance schließt, die in der Setup-Vorrichtung gestartet wurde.

Der "Test" ist sehr einfach, sehen wir uns die möglichen Ergebnisse an:

  1. Der Test wird ohne Probleme ausgeführt. Dies ist das bestmögliche Ergebnis.
  2. Wenn UMM aktiviert ist, schließt ein Benutzer die MSPaint-instance während der Ausführung. In diesem Fall wird der Test erfolgreich ausgeführt, aber die Bereinigung schlägt mit einer InvalidOperationException fehl.
  3. Wenn UMM aktiviert ist, schließt ein Benutzer die MSPaint-instance während der Ausführung. In diesem Fall protokolliert der UMM-Code einen Fehler, der zeigt, dass der Prozess geschlossen wurde. Die Bereinigung schlägt wie im Fall (2) fehl.

Wenn UMM aktiviert ist, wird das fehlerhafte Verhalten sofort gemeldet und wirkt sich direkt auf das Testergebnis aus. Dies ist ein viel besseres Testmuster, da Fehler so früh wie möglich gemeldet werden und zusätzlicher Kontext bereitgestellt wird, um beim Debuggen oder Verstehen von Testfehlern zu helfen.