2009-12-15 35 views
5

Sto scrivendo un test case per il controllo utente che richiederà l'utilizzo di MessageBox.Show per l'azione dell'utente che richiede di elaborare o annullare l'operazione. Come posso progettare il mio test dell'unità per simulare l'interazione dell'utente per procedere ?.Unit test Winforms UI

Non voglio refactoring per spostare la logica al livello intermedio. Questo è un semplice caso di ottenere il consenso dell'utente e procedere con la chiamata di livello medio. Sarà utile anche un'interfaccia utente di ristrutturazione di aiuto/idee per questo scenario.

+0

Quindi vuoi testare cosa fa il tuo controllo quando fa clic su ognuno di questi? o il test stesso ha una finestra di dialogo di blocco messagebox per vedere se il livello intermedio è sicuro da testare? – Maslow

risposta

6

Fare clic su un pulsante non è altro che invocare l'evento click corrispondente. Quindi potresti voler costruire il tuo test intorno a questo.

Ancora meglio (se questo non è ancora il caso), sposta il tuo codice fuori dal frontend e costruisci le tue unittests attorno alle azioni di business, altrimenti invocheresti facendo clic su un pulsante.

aggiornamento dopo modifica di autore
Non stanno andando a farlo funzionare finché non si è pronti a dividere le cose, non si può costruire il test di unità in tutto 'clicca qui', 'click lì '. Immaginate il seguente codice:

private int MyFunction() 
{ 
    bool insideVariable = false; 
    if(insideVariable) 
     return 1; 
    else 
     return 2; 
} 

Sarà mai essere in grado di unit test il caso in cui insideVariable è impostata su true; È possibile:

  1. refactoring del codice in modo l'affermazione return 1 è da qualche parte nel vostro livello intermedio
  2. refactoring in modo che la dichiarazione return 1 è un metodo nella GUI. È quindi possibile testare tale funzione.

I frontend delle applicazioni devono essere facilmente sostituibili, quindi non è necessario archiviare la logica aziendale. I test unitari sono solo un altro frontend che vivono accanto alla tua GUI principale.

+0

Posso usare SendKeys.SendWait roba simile, ma il problema qui è ShowDialog è una chiamata bloccante – SKG

+0

Non dovresti provare a fare veramente clic sul pulsante, ma solo qualcosa come 'nuovo Form1(). Button1_Click (this, null)' . –

+2

+1 - Se l'interfaccia utente contiene una logica sufficiente a duplicare la sua azione richiede effettivamente l'utilizzo del codice dell'interfaccia utente, l'interfaccia utente contiene troppa logica. Potrebbe valere la pena di notare le eccezioni - la logica di presentazione è sempre delicata a questo riguardo - ma in generale il codice testabile non vive nell'interfaccia utente per cominciare. –

3

Fornire una soluzione sarebbe molto più semplice con il metodo UI oi metodi correlati pubblicati. Anche vedere il TestMethod (s) potrebbe aiutare anche i metodi incompleti.

Se capisco che lo scopo del test è determinare cosa succede sulle diverse possibilità di clic?

Si potrebbe impostare il metodo effettivo che fa scattare il MessageBox utilizzando Inversion of Control e Dependency Injection come questo:

public class ClassUnderTest 
{ 
    private static Func<string, string, MessageBoxButtons, DialogResult> 
     _messageBoxLocator = MessageBox.Show; 
    public static Func<string, string, MessageBoxButtons, DialogResult> 
     MessageBoxDependency 
    { 
     get { return _messageBoxLocator; } 
     set { _messageBoxLocator = value; } 
    } 

    private void MyMethodOld(object sender, EventArgs e) 
    { 
     if (MessageBox.Show("test", "", MessageBoxButtons.YesNo) == 
      System.Windows.Forms.DialogResult.Yes) 
     { 
      //Yes code 
      AnsweredYes = true; 
     } 
     else 
     { 
      //No code 

     } 
    } 

    public bool AnsweredYes = false; 

    public void MyMethod(object sender, EventArgs e) 
    { 
     if (MessageBoxDependency(
        "testText", "testCaption", MessageBoxButtons.YesNo) 
      == 
      System.Windows.Forms.DialogResult.Yes) 
     { 
      //proceed code 
      AnsweredYes = true; 
     } 
     else 
     { 
      //abort code 
     } 


    } 
} 

e quindi il metodo di prova (ricordarsi di includere il using Microsoft.VisualStudio.TestTools.UnitTesting; in alto) sarebbe come questo:

[TestMethod] 
    public void ClassUnderTest_DefaultAnsweredYes_IsFalse() 
    { 
     var classUnderTest = new ClassUnderTest(); 
     Assert.AreEqual(false, classUnderTest.AnsweredYes); 
    } 
    [TestMethod] 
    public void MyMethod_UserAnswersYes_AnsweredYesIsTrue() 
    { 
     //Test Setup 
     Func<string, string, MessageBoxButtons, DialogResult> 
      fakeMessageBoxfunction = 
        (text, caption, buttons) => 
        DialogResult.Yes; 

     //Create an instance of the class you are testing 
     var classUnderTest = new Testing.ClassUnderTest(); 
     var oldDependency = Testing.ClassUnderTest.MessageBoxDependency; 
     Testing.ClassUnderTest.MessageBoxDependency = fakeMessageBoxfunction; 
     try 
     { 
      classUnderTest.MyMethod(null, null); 
      Assert.AreEqual(true, classUnderTest.AnsweredYes); 
      //Assert What are you trying to test? 
     } 
     finally 
     { //Ensure that future tests are in the default state 
      Testing.ClassUnderTest.MessageBoxDependency = oldDependency; 
     } 
    }