Dieser Artikel wurde maschinell übersetzt.

Testlauf

Tests durch Fault Injection mit TestApi

James McCaffrey

Downloaden des Codebeispiels

Testen der Fault Injection-ist der Prozess der absichtlich einen Fehler in einer Anwendung unter Testbedingungen einfügen und dann beim Ausführen der Anwendung, um zu bestimmen, ob die Anwendung ordnungsgemäß mit dem Fehler behandelt.Fault Injection-Tests kann mehrere verschiedene Formen annehmen.Im Artikel dieses Monats erklären ich, wie Sie in .NET Anwendungen zur Laufzeit mithilfe einer Komponente der Bibliothek TestApi Fehlern führen können.

Am besten für Sie finden in dieser Spalte worauf ich bin besteht darin, einen Blick auf den Screenshot in Abbildung 1 in Anspruch nehmen. Das Bildschirmfoto zeigt, dass ich Fault Injection-Tests auf ein dummy .NET Windows Forms-Anwendung mit dem Namen TwoCardPokerGame.exe ausgeführt wird. In der Befehlsshell wird ein C#-Programm mit dem Namen FaultHarness.exe ausgeführt. Diese ändert des normalen Verhaltens der zu testenden Anwendung, damit die Anwendung eine Ausnahme der dritten Mal löst, die ein Benutzer auf die Schaltfläche mit der Bezeichnung auswerten klickt. In diesem Fall zwei Karten Poker-Anwendung verarbeitet die Anwendungsausnahme nicht ordnungsgemäß, und das Ergebnis ist das vom System generierte Meldungsfeld.

Fault Injection in Aktion testen

Abbildung 1 Fault Injection in Aktion testen

Let’s näher bei diesem Szenario einige Details Beteiligten berücksichtigt. Wenn FaultHarness.exe aus der Befehlsshell gestartet wird, bereitet die Testumgebung hinter den Kulissen Profilerstellungs-Code, der die normale Codeausführung von TwoCard ­ PokerGame.exe abgefangen wird. Der Fault Injection-Sitzung wird aufgerufen.

Die Fault Injection-Sitzung verwendet eine DLL, um Überwachen der Aufrufe an die Anwendung Button2_Click-Methode, die Ereignishandler für die Schaltfläche Evaluate ist zu starten. Die Fault Injection-Sitzung wurde konfiguriert, so, dass der ersten zwei Mal ein Benutzer auf die Schaltfläche "auswerten" der Anwendung klickt verhält sich wie codiert, aber bei der dritten klicken Sie auf die Fehlertoleranz-Sitzung wird die Anwendung eine Ausnahme vom Typ System.ApplicationException.

Die Fault-Sitzung Sitzungsaktivität und einen Satz von Dateien auf dem Hostcomputer Test protokolliert. Abbildung 1-bemerken Sie, die ersten beiden Anwendung Bewerten von Karten geben klicken Paare Arbeit ordnungsgemäß, aber der dritten Klick hat eine Ausnahme verursacht.

In den folgenden Abschnitten werde ich kurz beschreiben das dummy Two-Poker Kartenspiel unter Anwendung testen, präsentieren und Erläutern Sie ausführlich den Code im Programm FaultHarness.exe in Abbildung 1 angezeigt und bieten einige Tipps an, wenn die Verwendung der Fault Injection-Tests geeignet ist und wenn alternative Verfahren besser geeignet sind. Obwohl FaultHarness.exe Programm selbst recht einfach ist, und die meisten schwierige Aufgaben von TestApi-DLLs im Hintergrund ausgeführt wird, erfordert verstehen, und ändern den Code, den ich hier vorstellen entsprechend Ihren eigenen Tests Szenarios solide Kenntnisse der Programmierung .NET-Umgebung. Sagte, selbst wenn Sie ein Anfänger .NET sind, sollte meinen Erklärungen zu viel problemlos folgen. Ich bin sicher, Sie der Diskussion der Fault Injection eine interessante und möglicherweise nützliche Ergänzung zu Ihrem Toolset finden.

Die zu testende Anwendung

Testenden unechten Anwendung ist eine einfache, aber repräsentative c# WinForm-Anwendung, die simuliert eine hypothetische Kartenspiel, das zwei Karten Poker aufgerufen. Die Anwendung besteht aus zwei Hauptkomponenten: TwoCardPokerGame.exe bietet die Benutzeroberfläche und die TwoCardPokerLib.dll die zugrunde liegenden Funktionen bereitstellt.

Die Spiele-DLL erstellen ich Visual Studio 2008 gestartet und aktiviert die Vorlage für c#-Klassenbibliothek aus der Datei | im Dialogfeld Neues Projekt. Ich den Namen der Bibliothek TwoCardPokerLib. Abbildung 2 , wird die allgemeine Struktur der Bibliothek angezeigt. Der Code für TwoCardPokerLib ist zu lang, um in ihrer Gesamtheit in diesem Artikel vorhanden. Der vollständige Quellcode für die Bibliothek TwoCardPokerLib und die FaultHarness Fault Injection-Testumgebung steht im Codedownload, der diesen Artikel begleitet.

Abbildung 2 Der Bibliothek TwoCardPokerLib

using System;
namespace TwoCardPokerLib {
  // -------------------------------------------------
  public class Card {
    private string rank;
    private string suit;
    public Card() {
      this.rank = "A"; // A, 2, 3, . . ,9, T, J, Q, K
      this.suit = "c"; // c, d, h, s
    }
    public Card(string c) { . . . }
    public Card(int c) { . . . }
    public override string ToString(){ . . . }
    public string Rank { . . . }
    public string Suit { . . . }
    public static bool Beats(Card c1, Card c2) { . . . }
    public static bool Ties(Card c1, Card c2) { . . . }
  } // class Card

  // -------------------------------------------------
  public class Deck {
    private Card[] cards;
    private int top;
    private Random random = null;

    public Deck() {
      this.cards = new Card[52];
      for (int i = 0; i < 52; ++i)
        this.cards[i] = new Card(i);
      this.top = 0;
      random = new Random(0);
    }

    public void Shuffle(){ . . . }
    public int Count(){ . . . } 
    public override string ToString(){ . . . }
    public Card[] Deal(int n) { . . . }
    
  } // Deck

  // -------------------------------------------------
  public class Hand {
    private Card card1; // high card
    private Card card2; // low card
    public Hand(){ . . . }
    public Hand(Card c1, Card c2) { . . . }
    public Hand(string s1, string s2) { . . . }
    public override string ToString(){ . . . }
    private bool IsPair() { . . . }
    private bool IsFlush() { . . . }
    private bool IsStraight() { . . . }
    private bool IsStraightFlush(){ . . . }
    private bool Beats(Hand h) { . . . }
    private bool Ties(Hand h) { . . . }
    public int Compare(Hand h) { . . . }
    public enum HandType { . . . }
    
 } // class Hand

} // ns TwoCardPokerLib

Der Anwendungscode für die Benutzeroberfläche

Sobald der zugrunde liegenden TwoCardPokerLib Bibliothekscode abgeschlossen ich hatte erstellt habe ich eine dummy-Benutzeroberflächen-Komponente. Ein neues Projekt, das in Visual Studio 2008 mit der Vorlage für C#-Windows Forms-Anwendung gestartet wurde und mit der Anwendung TwoCardPokerGame.

Verwenden Visual Studio-Designer, ich ein Label-Steuerelement aus der Toolbox-Auflistung auf die Anwendung Entwurfsoberfläche gezogen, und geändert Text-Eigenschaft des Steuerelements aus “ textBox1 ”, “ zwei Karten Poker ”. Als Nächstes fügte ich zwei weitere Label-Steuerelemente (“ Ihrer Hand ” und “ Computer's Hand ”), zwei Textfeld-Steuerelemente, zwei Button-Steuerelemente (“ Karten geben ” und “ Evaluate ”) und ein ListBox-Steuerelement. Wurde die Standardnamen für die Steuerung der acht Steuerelemente nicht geändert, textBox1, textBox2 button1 und dies auf.

Sobald der Entwurf vorhanden war, doppelgeklickt ich auf das button1-Steuerelement, um Visual Studio generieren ein Ereignis-Handler Skelett für die Schaltfläche und die Datei Form1.cs in den Codeeditor geladen haben. An dieser Stelle ich Ebene auf das TwoCardPokerGame-Projekt im Projektmappen-Explorer, aus dem Kontextmenü die Option Verweis hinzufügen ausgewählt und auf die Datei TwoCardPokerLib.dll verwiesen wird. In "Form1.cs", hinzugefügt eine using-Anweisung damit würde nicht voll qualifizieren, die Klassennamen in der Bibliothek werden muss.

Anschließend hinzugefügt habe ich in meiner Anwendung vier Gültigkeitsbereich der Klasse statische Objekte:

namespace TwoCardPokerGame {
  public partial class Form1 : Form {
    static Deck deck;
    static Hand h1;
    static Hand h2;
    static int dealNumber; 
...

H1-Objekt ist das Lager für den Benutzer und h2 wird das Lager für den Computer. Dann hinzugefügt habe ich Initialisierungscode für den Formular-Konstruktor:

public Form1() {
  InitializeComponent();
  deck = new Deck();
  deck.Shuffle();
  dealNumber = 0;
}

Der Deckgenerator-Konstruktor erstellt ein Deck 52 Karten in der Reihenfolge das Ass Kreuz in der König Pik und die zufällige Wiedergabe-Methode
randomizes die Reihenfolge der Karten in den Ausgangsstapel.

Anschließend hinzugefügt habe ich die Codelogik der der Button1_Click-Methode, wie dargestellt in Abbildung 3 . Für jede der beiden Händen rufe ich die Deck.Deal-Methode, um zwei Karten aus dem PowerPoint-Objekt zu entfernen. Dann ich zwei Karten an die Hand-Konstruktor übergeben, und der Wert des Zeigers in einem TextBox-Steuerelement angezeigt. Beachten Sie, dass die Button1_Click-Methode Ausnahme, behandelt indem eine Meldung angezeigt, in das ListBox-Steuerelement.

Abbildung 3 behandeln die Karten

private void button1_Click(
  object sender, EventArgs e) { 

  try  {
    ++dealNumber;
    listBox1.Items.Add("Deal # " + dealNumber);
    Card[] firstPairOfCards = deck.Deal(2);
    h1 = new Hand(firstPairOfCards[0], firstPairOfCards[1]);
    textBox1.Text = h1.ToString();

    Card[] secondPairOfCards = deck.Deal(2);
    h2 = new Hand(secondPairOfCards[0], secondPairOfCards[1]);
    textBox2.Text = h2.ToString();
    listBox1.Items.Add(textBox1.Text + " : " + textBox2.Text);
  }
  catch (Exception ex) {
    listBox1.Items.Add(ex.Message);
  }
}

Als Nächstes doppelgeklickt in der Visual Studio-Designer-Fenster ich auf dem Steuerelement button2 Ereignishandler des Steuerelements automatisch generieren
Skelett. Sie haben einige einfachen Code zum Vergleichen von zwei Lager-Objekte, und zeigen Sie eine Meldung in das ListBox-Steuerelement hinzugefügt. Beachten Sie, dass die Button2_Click-Methode alle Ausnahmen, die nicht direkt behandeln:

private void button2_Click(
  object sender, EventArgs e) {
  int compResult = h1.Compare(h2);
  if (compResult == -1)
    listBox1.Items.Add(" You lose");
  else if (compResult == +1)
    listBox1.Items.Add(" You win");
  else if (compResult == 0)
    listBox1.Items.Add(" You tie");

  listBox1.Items.Add("-------------------------");
}

Der Fault Injection-Testumgebung

Vor dem Erstellen der Fault Injection-Testumgebung in Abbildung 1 dargestellt, heruntergeladen ich den Schlüssel DLLs auf Mein Test-Hostcomputer. Diese DLLs sind Teil einer Auflistung von .NET-Bibliotheken, die mit dem Namen TestApi und testapi.codeplex.com-gefunden werden können.

Die TestApi-Bibliothek ist eine Sammlung von Dienstprogrammen Software testen-bezogenen. Die Bibliothek TestApi umfasst eine Reihe von verwaltetem Code Fault Injection-APIs. (Weitere Informationen über diese blogs.msdn.com/b/ivo_manolov/archive/2009/11/25/9928447.aspx-.) Ich heruntergeladen neueste Fault Injection-APIs-Version, die in meinem Fall wurde Version 0,4 und Entzippen den Download. Ich werde erklären, was im Download ist und die Fault Injection-Binärdateien in Kürze angelegt.

0,4-Version unterstützt Fault Injection-Tests bei Anwendungen mit .NET Framework 3.5 erstellt. TestApi-Bibliothek ist in der aktiven Entwicklung so, dass Sie die CodePlex-Website auf Aktualisierungen, die Techniken überprüfen soll, die ich in diesem Artikel vorstellen. Darüber hinaus sollten Sie die Überprüfung auf Aktualisierungen und Tipps zu den Blog von Bill Liu, der Hauptentwickler TestApi Fault Injection-Bibliothek blogs.msdn.com/b/billliu/-.

Zum Erstellen der Fault Injection-Testumgebung ich ein neues Projekt in Visual Studio 2008 gestartet und aktiviert die Vorlage für C#-Konsolenanwendungen. Mit der Anwendung FaultHarness und die Vorlage Programm einige minimalen Code hinzugefügt (siehe Abbildung 4 ).

Abbildung 4 FaultHarness

using System;
namespace FaultHarness {
  class Program {
    static void Main(string[] args) {
      try {
        Console.WriteLine("\nBegin TestApi Fault Injection environmnent session\n");

        // create fault session, launch application

        Console.WriteLine("\nEnd TestApi Fault Injection environment session");
      }
      catch (Exception ex) {
        Console.WriteLine("Fatal: " + ex.Message);
      }
    }
  } // class Program
} // ns

I drücken Sie die Taste <F5> zum Erstellen und ausführen das Testumgebung Skelett, das einen \bin\Debug Ordner im Stammordner FaultHarness erstellt.

Der Download TestApi verfügt über zwei Hauptkomponenten. Die erste ist die TestApiCore.dll, die im Ordner Binaries des entzippt Downloads gespeichert wurde. Diese DLL kopiert in das Stammverzeichnis der Anwendung FaultHarness. Dann I Ebene auf das FaultHarness-Projekt im Projektmappen-Explorer ausgewählten Verweis hinzufügen und auf die TestApiCore.dll zeigt. Als Nächstes hinzugefügte eine using-Anweisung für Microsoft.Test.FaultInjection an den Anfang der meine Testumgebung Problemcode damit meine Testumgebung Code direkt auf die Funktionalität in TestApiCore.dll zugreifen konnte. Auch hinzugefügte using System.Diagnostics-Anweisung daran, wie Sie in Kürze sehen werden, verarbeiten und ProcessStartInfo Zugriff auf Klassen in diesem Namespace werden soll.

Die zweite wichtige Komponente in der Fault Injection-Download ist ein Ordner mit dem Namen FaultInjectionEngine. Dies enthält 32-Bit- und 64-Bit-Versionen von FaultInjectionEngine.dll. Kopiert den gesamten Fault ­ InjectionEngine-Ordner in den Ordner Meine FaultHarness in meinem Fall C:\FaultInjection\FaultHarness\bin\Debug\ ausführbare Datei enthält. Die 0,4 ich Fault Injection-System-Version erfordert den FaultInjectionEngine Ordner in demselben Speicherort wie die Testumgebung, die ausführbare. Darüber hinaus erfordert das System die Anwendung unter Testbinärdateien in demselben Ordner wie die ausführbare Testumgebung gefunden werden, so dass die kopierten Dateien TwoCardPokerGame.exe und TwoCard ­ PokerLib.dll in C:\FaultInjection\FaultHarness\bin\Debug\.

Zum zusammenfassen, wenn TestApi Fault Injection-System verwenden, ist ein guter Ansatz zum Generieren einer Testumgebung Gerüst, und führen Sie so, dass eine Testumgebung \bin\Debug Verzeichnis wird erstellt, und dann TestApiCore.dll-Datei im Stammverzeichnis Testumgebung platzieren, platzieren den Ordner FaultInjectionEngine in \bin\Debug und \bin\Debug sowie die Anwendung unter Testbinärdateien (exe und DLL) versehen.

Mit dem TestApi Fault Injection-System erfordert, dass Sie die Methode in der zu testenden Anwendung testenden Anwendung angeben, die einen Fehler der Bedingung auslösen, die ausgelöst wird, einen Fehler und die Art des Fehlers, der ausgelöst wird:

string appUnderTest = "TwoCardPokerGame.exe";
string method = 
  "TwoCardPokerGame.Form1.button2_Click(object, System.EventArgs)";
ICondition condition =
  BuiltInConditions.TriggerEveryOnNthCall(3);
IFault fault =
  BuiltInFaults.ThrowExceptionFault(
    new ApplicationException(
    "Application exception thrown by Fault Harness!"));
FaultRule rule = new FaultRule(method, condition, fault);

Beachten Sie, dass, da das System die Anwendung getestet werden im selben Ordner wie die ausführbare Testumgebung erforderlich ist, der Namen der Anwendung unter ausführbare Testdatei nicht den Pfad zum Speicherort muss.

Gibt den Namen der Methode, die den eingefügten Fehler auslöst, ist eine häufige Ursache für Probleme für TestApi Fault Injection-Anfänger. Der Methodenname muss in der Form Name ­ space.Class.Method(args) vollständig qualifiziert werden. Meine bevorzugte Verfahren ist mit das Tool ildasm.exe, um mich auslösenden Methodensignatur bestimmen zu testenden Anwendung zu untersuchen. Im besonderen Visual Studio-Befehl Tools Shell ich ildasm.exe zu starten, zeigen Sie auf die zu testende Anwendung, und doppelklicken Sie auf die Zielmethode. Abbildung 5 zeigt ein Beispiel mithilfe von ildasm.exe untersuchen Sie die Signatur für die -Methode.

mithilfe von ILDASM untersuchen Methodensignaturen

Abbildung 5 mithilfe von ILDASM untersuchen Methodensignaturen

Bei der Angabe der Methodensignatur Trigger Sie verwenden nicht den Rückgabetyp der Methode, und verwenden Sie keine Parameternamen. Beim Abrufen der Methodensignatur richtig manchmal benötigt ein wenig ausprobieren. Beispielsweise verwendet auf meinem ersten Versuch Button2_Click abzielen:

TwoCardPokerGame.Form1.button2_Click(object,EventArgs)

Ich musste es zu korrigieren:

TwoCardPokerGame.Form1.button2_Click(object,System.EventArgs)

Der TestApi-Download enthält eine Dokumentationsordner Dokumentseite Konzepte, die gute Anleitungen für verschiedene Arten von Methodensignaturen, z. B. Konstruktoren, generische Methoden, Eigenschaften ordnungsgemäß zu erstellen und das Überladen von Operatoren enthält. Hier ich eine Methode, die in der zu testenden Anwendung abzielen, aber ich konnte haben auch Ziel eine Methode in der zugrunde liegenden 2 ­ CardPokerLib.dll, z. B.:

string method = "TwoCardPokerLib.Deck.Deal(int)"

Nachdem Sie die Trigger-Methode, ist der nächste Schritt die Bedingung angeben, unter der der Fehler in der zu testenden Anwendung eingefügt werden. In meinem Beispiel verwendete TriggerEveryOnNthCall(3), die wie Sie gesehen haben einen Fehler jedem dritten Fügt den Trigger wird die Methode aufgerufen. TestApi Fault Injection-System verfügt über einen ordentlichen Satz Trigger Bedingungen einschließlich TriggerIfCalledBy(method) TriggerOnEveryCall und andere.

Wenn die Auslöserbedingung angegeben haben, wird im nächste Schritt an, die in das zu testende System eingefügt werden, wird den Typ des Fehlers. BuiltInFaults.ThrowExceptionFault verwendet. Zusätzlich zu Fehlern durch eine Ausnahme hat das TestApi Fault Injection-System integrierte Rückgabetyp-Fehlern, die fehlerhafte Rückgabewerte in Ihrer Anwendung zur Laufzeit eingefügt werden können. Beispielsweise bewirkt das Trigger-Methode (vermutlich falschen) der Wert-1 zurückgegeben:

IFault f = BuiltInFaults.ReturnValueFault(-1)

Nach der Fault-Trigger-Methode Bedingung und Fehlertoleranz Art angegeben wurden, im nächste Schritt erstellen eine neue FaultRule und die Regel an einen neuen FaultSession übergeben wird:

FaultRule rule = new FaultRule(method, condition, fault);
Console.WriteLine(
  "Application under test = " + appUnderTest);
Console.WriteLine(
  "Method to trigger injected runtime fault = " + method);
Console.WriteLine(
  "Condition which will trigger fault = On 3rd call");
Console.WriteLine(
  "Fault which will be triggered = ApplicationException");
FaultSession session = new FaultSession(rule);

Ist mit allen Preliminaries an Stelle der letzte Teil der Testumgebung Fehlercode schreiben programmgesteuert in die Umgebung für die Fehlertoleranz Sitzungen testenden Anwendung starten:

ProcessStartInfo psi = 
  session.GetProcessStartInfo(appUnderTest);
Console.WriteLine(
  "\nProgrammatically launching application under test");
Process p = Process.Start(psi);
p.WaitForExit();
p.Close();

Wenn Sie die Fault-Umgebung ausführen, starten Sie in der Fault-Sitzung mit FaultInjection ­ Engine.dll testenden Anwendung ansehen für Situationen, in denen die Trigger-Methode aufgerufen, wird Wenn die Auslöserbedingung erfüllt ist. Die Tests werden hier manuell durchgeführt, aber Sie können auch Testautomatisierung in einem Fault-Sitzung ausführen.

Während die Fault-Sitzung ausgeführt wird, protokolliert Informationen über die Sitzung in das aktuelle Verzeichnis, d. h. das Verzeichnis, das die ausführbare Datei Fault-Umgebung und die Anwendung unter ausführbare Testdatei enthält. Sie können überprüfen, dass diese Protokolldateien zu helfen, Probleme zu beheben, die auftreten können, während Sie Ihre Fault Injection-Umgebung entwickeln.

Discussion

Das Beispiel und Erklärungen, die hier vorgestellten sollten Sie mit dem Erstellen einer Fault Injection-Testumgebung für Ihre eigene Anwendung unter Testbedingungen betriebsbereit abrufen. Wie bei aller Aktivitäten, die den Prozess der Softwareentwicklung gehört, Sie werden Ressourcen beschränkt sind, und Analysieren Sie die Kosten und Vorteile der Ausführung fault Injection-Tests. Im Fall von einigen Anwendungen benötigt der Aufwand zum Erstellen der Fault Injection-Tests möglicherweise nicht sinnvoll, aber es gibt viele Tests Szenarios, in denen Fault Injection-Tests sehr wichtig ist. Stellen Sie sich vor Software, die ein medizinischen Gerät oder ein System Flug steuert. In Fällen wie diesen muss Anwendungen absolut robuste und alle Arten von unerwarteten Fehlern ordnungsgemäß zu verarbeiten.

Eine bestimmte Irony ist Fault Injection-Tests beteiligt. Die Idee ist, wenn Sie die Situationen erwarten können eine Ausnahme auftreten kann, können Sie in der Theorie oft programmgesteuert Schutz vor dieser Ausnahme und das richtige Verhalten, guarding Verhalten zu testen. Ist jedoch auch in solchen Situationen Fault Injection-Tests nützlich für das Generieren von schwierig, Ausnahmen zu erstellen. Darüber hinaus ist es möglich, das Einschleusen von Fehlern, die schwer zu erwarten, wie z. B. System.OutOfMemoryException.

Testen der Fault Injection-ist im Zusammenhang mit und manchmal mit Mutation testen verwechselt. Testen von Mutation absichtlich Fehler in das zu testende System einfügen, aber führen Sie eine vorhandene Testsuite gegen das fehlerhafte System, um zu ermitteln, ob die Testsuite erstellt neue Fehler abfängt. Testen die Mutation ist eine Methode zum Messen der Effektivität der Test Suite und letztendlich Testfall Abdeckung zu erhöhen. Wie Sie in diesem Artikel gesehen haben, ist der primäre Zweck des Fault Injection-Tests, um festzustellen, ob das zu testende System ordnungsgemäß Fehler behandelt.

Dr.James McCaffrey  arbeitet für Volt Information Sciences Inc., wo er verwaltet die technische Schulungen für Softwareentwickler bei Microsoft Redmond, Washington, Campus. Er wird in verschiedenen Microsoft-Produkten, einschließlich Internet Explorer und MSN Search gearbeitet. Dr. McCaffrey ist der Autor von “ .NET Test Automation Recipes ” (Apress, 2006) und kann unter jammc@microsoft.com-erreicht werden.

Dank an die folgenden technischen Experten für die Überprüfung der in diesem Artikel: Bill Liu und Paul Newson