Il presente articolo è stato tradotto automaticamente.

Esecuzione di test

Test Fault Injection con TestApi

James McCaffrey

Scaricare il codice di esempio

James McCaffreyTest di fault injection è il processo di inserimento deliberatamente un errore in un'applicazione da testare e quindi l'esecuzione dell'applicazione per determinare se l'applicazione gestisce l'errore correttamente. Test di fault injection possono assumere forme diverse diverse. Nell'articolo di mese questo illustrare come è possibile introdurre errori in applicazioni .NET in fase di esecuzione utilizzando un componente della libreria TestApi.

Il modo migliore vedere dove sta angolare in questa colonna è di dare un'occhiata alla schermata in di Figura 1. La schermata mostra che sto eseguendo fault injection test su un'applicazione Windows Form .NET fittizia denominata TwoCardPokerGame.exe. Esecuzione di un programma C# denominato FaultHarness.exe nella shell dei comandi. Modifica il funzionamento normale dell'applicazione sottoposta a test in modo che l'applicazione genera un tempo la terza eccezione che si fa clic sul pulsante con etichettato Evaluate. In questa situazione, l'applicazione Poker biglietto due non gestisce correttamente l'eccezione di applicazione e il risultato è la finestra di messaggio generato dal sistema.

Figure 1  Fault Injection Testing in Action

Figura 1 di fault injection test in azione

Richiedere Let’s esaminate in questo scenario considerare alcuni dettagli coinvolti. Quando FaultHarness.exe viene avviato dalla shell dei comandi, dietro le quinte l'harness Prepara codice di analisi verrà intercettare l'esecuzione normale codice di TwoCard ­ PokerGame.exe. Si tratta della sessione di fault injection.

La sessione di fault injection utilizza una DLL per avviare la riproduzione per le chiamate al metodo Button2_Click dell'applicazione è il gestore eventi per il pulsante denominato Evaluate. La sessione di fault injection è stata configurata in modo che il primo due volte che un utente fa clic sul pulsante valuta, l'applicazione si comporta come codificato, ma nel terzo clic la sessione di errore, l'applicazione genera un'eccezione di tipo System.ApplicationException.

La sessione di errore registra l'attività della sessione e registra una serie di file al computer host di test. Notare nella Figura 1 che l'applicazione primi due valuta transazione scegliere lavoro coppie correttamente, ma il terzo clic ha generato un'eccezione.

Nelle sezioni che seguono verrà brevemente descrivere il fittizio due Card Poker Game applicazione sottoposta a test, presentare e descrivere in dettaglio il codice nel programma FaultHarness.exe mostrato in di Figura 1 e forniscono suggerimenti su quando è appropriato utilizzare fault injection test e quando tecniche alternative sono più adatte. Anche se il programma FaultHarness.exe è abbastanza semplice e la maggior parte del lavoro difficile avviene dietro le quinte dalle DLL TestApi, comprensione e modificare il codice che qui presentate per soddisfare i propri test scenari è necessario una conoscenza approfondita dell'ambiente di programmazione. NET. Che dice, anche se siete principianti. NET, è possibile seguire le spiegazioni senza eccessiva difficoltà. Si è sicuro che troverete la discussione di fault injection un'aggiunta probabilmente utile e interessante per il set di strumenti.

Applicazione sottoposta a test

Applicazione fittizia sottoposta a test è un'applicazione Windows Form C# semplicistico, ma rappresentativa che simula un gioco di carte ipotetica denominato Two Card Poker. L'applicazione è costituita da due componenti principali: TwoCardPokerGame.exe fornisce l'interfaccia utente e TwoCardPokerLib.dll fornisce la funzionalità sottostante.

Per creare la DLL di gioco avviato Visual Studio 2008 e selezionato il modello di libreria di classi C# dal file | finestra di dialogo Nuovo progetto. È denominata raccolta TwoCardPokerLib. La struttura generale della libreria viene presentata in di Figura 2. Il codice per TwoCardPokerLib è troppo lungo per la presentazione nella sua interezza in questo articolo. Il codice sorgente completo per la libreria TwoCardPokerLib e l'harness di FaultHarness fault injection è disponibile nel download del codice che accompagna questo articolo.

Figura 2 La libreria 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

Il codice dell'interfaccia utente dell'applicazione

Una volta ho avuto il codice della libreria TwoCardPokerLib sottostante finito, ho creato un componente dell'interfaccia utente fittizio. Avvio di un nuovo progetto in Visual Studio 2008 utilizzando il modello applicazione Windows Form C# e denominato TwoCardPokerGame dell'applicazione.

Utilizzando la finestra di progettazione di Visual Studio, trascinato un controllo Label dall'insieme di strumenti nell'area di progettazione dell'applicazione e modificati proprietà Text del controllo da “ textBox1 ” per “ due Card Poker. ” Quindi ho aggiunto due ulteriori controlli Label (“ del magazzino ” e “ computer della mano ”), due controlli TextBox, due controlli Button (“ gestiscono ” e “ Evaluate ”) e un controllo ListBox. Non modifica i nomi dei controlli predefiniti di tutti i controlli di otto, textBox1, textBox2, button1, quindi su.

Dopo la progettazione è stato posto, fatto doppio clic sul controllo button1 per generare uno scheletro di gestore eventi per il pulsante e caricare file Form1.cs nell'editor di codice Visual Studio. A questo punto è selezionata sul progetto TwoCardPokerGame nella finestra Esplora soluzioni, selezionate l'opzione Aggiungi riferimento dal menu di scelta rapida e punta al file TwoCardPokerLib.dll. In Form1.cs, ho aggiunto un utilizzo istruzione in modo che non sarebbe necessario qualificare in modo completo i nomi delle classi nella libreria.

Successivamente, ho aggiunto quattro oggetti static in ambito di classe alla mia applicazione:

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

Oggetto h1 è la giacenza per l'utente e h2 è la giacenza per il computer. Quindi ho aggiunto del codice di inizializzazione al costruttore di form:

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

Il costruttore deck crea un mazzo di 52 carte, nell'ordine da asso di fiori il re di picche e il metodo di riproduzione casuale
randomizes l'ordine delle schede nel mazzo.

Quindi ho aggiunto la logica del codice al metodo Button1_Click come illustrato in di Figura 3. Per ciascuna delle due mani, è possibile chiamare il metodo Deck.deal per rimuovere l'oggetto deck due schede. Quindi è possibile passare al costruttore di mano queste due schede e visualizzare il valore della lancetta in un controllo TextBox. Si noti che il metodo Button1_Click gestisce tutte le eccezioni visualizzando un messaggio nel controllo ListBox.

Figura 3 Gestione le schede

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

Successivamente, nella finestra di progettazione di Visual Studio aperto sul controllo button2 per generare automaticamente il gestore di eventi del controllo
scheletro. Aggiunta del codice semplice per confrontare due oggetti di magazzino e visualizzare un messaggio nel controllo ListBox. Si noti che il metodo Button2_Click non gestisce direttamente le eccezioni:

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("-------------------------");
}

L'harness di fault injection

Prima di creare l'harness injection errore illustrato in di Figura 1, la chiave dll ho scaricato al computer host di test. Queste DLL sono parte di un insieme di librerie .NET denominato TestApi e reperibile in testapi.codeplex.com .

La libreria TestApi è una raccolta di utilità software test correlate a. Inclusi nella libreria TestApi è un insieme di Managed Code Fault Injection API. (Ulteriori informazioni riguardo alla blogs.msdn.com/b/ivo_manolov/archive/2009/11/25/9928447.aspx .) Ho scaricato all'introduzione di errore più recente versione di API, che in questo caso è stato versione 0.4 e decompressa il download. Verrà spiegato che cos'è il download e la posizione subito i file binari di fault injection.

Versione 0.4 supporta fault injection test per le applicazioni create con .NET Framework 3.5. La libreria TestApi è in fase di sviluppo attivo, è consigliabile controllare il sito CodePlex per aggiornamenti per le tecniche presentate in questo articolo. Inoltre, se si desidera verificare la presenza di aggiornamenti e suggerimenti sul blog di Bill Liu, lo sviluppatore primario della TestApi fault injection raccolta, a blogs.msdn.com/b/billliu/ .

Per creare l'harness di fault injection avviato un nuovo progetto in Visual Studio 2008 e selezionato il modello applicazione Console C#. È denominata applicazione FaultHarness e aggiunta di codice minimo al modello di applicazione (vedere di Figura 4).

Figura 4 di 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

È possibile premere il tasto <F5> per generare ed eseguire la harness di base, creata una cartella \Bin\Debug nella cartella principale FaultHarness.

Download TestApi presenta due componenti principali. Il primo è TestApiCore.dll, situato nella cartella Binaries del download decompressi. Questa DLL copiata nella directory principale dell'applicazione FaultHarness. Quindi è selezionata sul progetto FaultHarness nella finestra Esplora soluzioni, selezionare Aggiungi riferimento e punta a TestApiCore.dll. Successivamente, ho aggiunto un utilizzo istruzione per Microsoft.Test.FaultInjection all'inizio del mio codice harness errore in modo che il codice harness può accedere direttamente la funzionalità in TestApiCore.dll. Ho inoltre aggiunto un utilizzo istruzione per System.Diagnostics perché, come vedrà a breve, è necessario accedere alle classi di processi e ProcessStartInfo da tale spazio dei nomi.

Il secondo componente chiave nel download fault injection è una cartella denominata FaultInjectionEngine. Contiene le versioni a 32 e 64 bit di FaultInjectionEngine.dll. L'intera cartella di InjectionEngine ­ errore copiate nella cartella contenente il mio FaultHarness eseguibile nel mio caso C:\FaultInjection\FaultHarness\bin\Debug\. La versione del sistema fault injection si era utilizzando 0,4 richiede la cartella FaultInjectionEngine nella stessa posizione l'harness eseguibile. Inoltre, il sistema richiede l'applicazione sottoposta a test binari trovarsi nella stessa cartella dell'eseguibile harness in modo copiato file TwoCardPokerGame.exe e TwoCard ­ PokerLib.dll C:\FaultInjection\FaultHarness\bin\Debug\.

Per riepilogare, se si utilizza il sistema di TestApi fault injection, un buon approccio consiste nel generare un scheletro harness ed eseguirlo in modo che una directory \Bin\Debug harness viene creato, quindi inserire file TestApiCore.dll nella directory radice harness, posizionare la cartella FaultInjectionEngine \Bin\Debug e posizionare l'applicazione sottoposta a test file binari (con estensione exe e DLL) in \Bin\Debug anche.

Utilizzando il sistema di TestApi fault injection, è necessario specificare l'applicazione da testare, il metodo nell'applicazione sottoposta a test genererà un errore, la condizione che genererà un errore e il tipo di errore che verrà attivata:

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

Si noti che, poiché il sistema richiede che l'applicazione sottoposta a test siano nella stessa cartella dell'eseguibile harness, il nome dell'applicazione in un file eseguibile del test non è necessario il percorso relativo.

Specifica il nome del metodo genererà l'errore inserito è una comune fonte di problemi per gli utenti inesperti di TestApi fault injection. Il nome del metodo deve essere qualificato completamente nello space.Class.Method(args) di ­ nome modulo. La tecnica consigliata consiste nell'utilizzare lo strumento ildasm.exe per esaminare l'applicazione sottoposta a test per determinare automaticamente la firma del metodo di attivazione. Da Visual Studio speciali strumenti di comando shell eseguire ildasm.exe, scegliere l'applicazione da testare, quindi fare doppio clic sul metodo di destinazione. Figura 5 Mostra un esempio di utilizzo di ildasm.exe per esaminare la firma del metodo Button2_Click.

Figure 5 Using ILDASM to Examine Method Signatures

Figura 5 utilizzando ILDASM per esaminare le firme di metodo

Quando si specifica la firma del metodo trigger, non utilizzare il tipo restituito del metodo e non utilizzare nomi di parametro. Ottenere la firma del metodo corretto talvolta richiede un po' di tentativi ed errori. Ad esempio, il primo tentativo di destinazione Button2_Click utilizzato:

TwoCardPokerGame.Form1.button2_Click(object,EventArgs)

È stato necessario correggerla per:

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

Download TestApi contiene una cartella documentazione contenente un documento concetti istruzioni buona correttamente creare diversi tipi di firme di metodo inclusi costruttori, metodi generici, le proprietà e gli operatori di overload. Questo campo di destinazione di un metodo che si trova nell'applicazione sottoposta a test, ma potesse hanno inoltre utilizzato un metodo nel sottostante due ­ CardPokerLib.dll, quali:

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

Dopo aver specificato il metodo di trigger, il passaggio successivo è per specificare la condizione in cui l'errore verrà inserita nell'applicazione sottoposta a test. Nel mio esempio ho utilizzato il trigger TriggerEveryOnNthCall(3), come si è visto inserisce un errore ogni terza volta viene chiamato il metodo. Sistema TestApi fault injection è ben compresi TriggerIfCalledBy(method), TriggerOnEveryCall e altre condizioni di trigger.

Dopo aver specificato la condizione del trigger, il passaggio successivo è per specificare il tipo di guasto che verrà inserita nel sistema sotto test. Ho utilizzato BuiltInFaults.ThrowExceptionFault. Oltre a errori di eccezione TestApi fault injection sistema presenta degli errori di tipo restituito predefiniti che consentono di inserire valori errati restituiti nell'applicazione sottoposta a test in fase di esecuzione. In questo modo, ad esempio, il metodo trigger restituire il valore -1 (presumibilmente errato):

IFault f = BuiltInFaults.ReturnValueFault(-1)

Dopo il metodo trigger fault, condizione e tipo di errore sono stati specificati, il passaggio successivo consiste nel creare un nuovo FaultRule e passare tale regola a un nuovo FaultSession:

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

Con tutti preliminaries posto, l'ultima parte di scrivere il codice di errore harness consiste nel lanciare a livello di programmazione l'applicazione sottoposta a test nell'ambiente di sessione di errore:

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

Quando si esegue l'harness fault, avvierà l'applicazione sottoposta a test durante la sessione di errore con il FaultInjection ­ Engine.dll visione per situazioni in cui viene chiamato il metodo trigger quando la condizione è true. I test vengono eseguiti manualmente qui, ma è anche possibile eseguire l'automazione di test in una sessione di errore.

Durante l'esecuzione della sessione di errore vengono registrate le informazioni sulla sessione nella directory corrente, ovvero la directory contenente l'eseguibile harness guasto e l'applicazione sottoposta a test eseguibile. È possibile esaminare i file registro per risolvere eventuali problemi che potrebbero verificarsi mentre si sta sviluppando l'harness di fault injection.

Discussione [Discussion]

L'esempio e le spiegazioni presentate in questo articolo dovrebbero ottenere è in esecuzione con la creazione di un harness injection guasto per la propria applicazione sottoposta a test. Come con qualsiasi attività che fa parte del processo di sviluppo del software, si verranno limitato alle risorse e si consiglia di analizzare i costi e i vantaggi dell'esecuzione di fault injection test. Nel caso di alcune applicazioni, lo sforzo richiesto per creare fault injection test potrebbe non essere utile, ma esistono molti scenari di test in cui fault injection test è molto importante. Si supponga di software che controlla una periferica medica o un sistema di volo. In casi come questi, applicazioni assolutamente devono essere affidabile e in grado di gestire correttamente tutti i tipi di errori imprevisti.

Un determinato irony sono coinvolte test di fault injection. L'idea è che, se è possibile prevedere le situazioni quando si verifica un'eccezione, è possibile in teoria spesso a livello di codice per prevenire l'eccezione e verificare il corretto funzionamento di tale comportamento guarding. Tuttavia, anche in tali situazioni, fault injection test è utile per generare difficile creare eccezioni. Inoltre, è possibile introdurre errori molto difficili da prevedere, ad esempio System.OutOfMemoryException.

Test di fault injection è correlata e talvolta confuse con test di mutazione. Nei test di mutazione, inserire deliberatamente errori del sistema sotto test ma eseguirà una suite di test esistenti contro il sistema difettosa per determinare se la suite di test rileva nuovi errori creati. Test di mutazione è un modo per misurare l'efficacia di suite di test e infine aumentare la copertura di test case. Come si è visto in questo articolo, l'obiettivo principale dei test di fault injection consiste nel determinare se il sistema da testare gestisce correttamente gli errori.

Dr.James McCaffrey* lavora per Volt Information Sciences Inc., dove gestisce la formazione tecnica degli ingegneri software funzioni Microsoft Redmond, WA, campus. Si è occupato di numerosi prodotti Microsoft, inclusi Internet Explorer e MSN Search. Dr. McCaffrey è autore di “ .NET Test Automation Recipes ” (Apress, 2006) e può essere contattato all'indirizzo jammc@microsoft.com .*

Grazie ai seguenti esperti tecnici per la revisione di questo articolo: Bill Liu e di Paul Newson