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:
- Der Test muss mit dem Metadatenwert "ProcessUnderTest" markiert werden. Dadurch kann UMM den prozess identifizieren, der getestet wird.
- 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:
- Wenn mehrere Instanzen des namens Process Under Test ausgeführt werden, wird die zuerst ermittelte instance verwendet.
- Der Benutzer, der die Testautomatisierung ausführt, muss über ausreichende Berechtigungen verfügen, um Debuggerereignisse aus dem Testprozess zu empfangen.
- 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:
- Der Test wird ohne Probleme ausgeführt. Dies ist das bestmögliche Ergebnis.
- 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.
- 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.