2011-12-19 17 views
8

Sto cercando di trovare il modo migliore per sganciare i messagebox dalla mia logica in modo da poterla correttamente smistare. Ora mi stavo chiedendo se sarebbe stato abbastanza se avessi creato una classe helper separata (C#) che potrei stubare più tardi per la mia messagebox. Per esempio:Messagebox e Unit test

static class messageBoxHelper 
{ 
    public static void msgBoxAlg(string message, string title, MessageBoxButtons buttons, MessageBoxIcon icons, bool show) 
    { 
     if (show) 
     { 
      MessageBox.Show(message, title, buttons, icons); 
     } 
} 

Poi ogni volta che avevo bisogno di usare un messagebox mi basta usare messageboxHelper/msgBoxAlg (...) invece di messagebox.show (...). Usando il bool show potrei abilitarlo o disabilitarlo durante i test.

Mi chiedo solo se questa è la "strada giusta". Con ciò intendo, esiste un modo più semplice o migliore per farlo correttamente? Non posso semplicemente abbandonare le messagebox, ma inoltrare informazioni "vitali" all'utente ("Vuoi chiudere questa finestra?" SÌ/NO ecc.). Potrebbe anche essere che non sto usando un'adeguata ingegneria del software, e dovrei disaccoppiare di più i miei messagebox dal mio bussinesslogic?

risposta

29

Sì, è giusto. Ma invece di classe statica, è necessario implementare IDialogService ed iniettarlo in classi che dovrebbero mostrare finestre di dialogo:

public interface IDialogService 
{ 
    void ShowMessageBox(...); 

    ... 
} 

public class SomeClass 
{ 
    private IDialogService dialogService; 

    public SomeClass(IDialogService dialogService) 
    { 
     this.dialogService = dialogService; 
    } 

    public void SomeLogic() 
    { 
     ... 
     if (ok) 
     { 
      this.dialogService.ShowMessageBox("SUCCESS", ...); 
     } 
     else 
     { 
      this.dialogService.ShowMessageBox("SHIT HAPPENS...", ...); 
     } 
    } 
} 

corso della prova l'SomeClass deve iniettare oggetto fittizio della IDialogService invece di uno vero e proprio.

Se è necessario testare più logica dell'interfaccia utente, considerare l'utilizzo del modello MVVM.

+0

Grazie, spiegazione molto chiara! –

+0

Amo il termine "IDialogService" come un'astrazione! – Samuel

2

Guardare in Inversion of Control (IoC), il principio fondamentale è che le cose che eseguono azioni ect devono essere passate come interfaccia, quindi si utilizza un contenitore IoC per collegare le interfacce a implementazioni specifiche per la propria app. Per ottenere facilmente questo nel tuo caso passa la cosa che fa le caselle di messaggio come interfaccia e nel tuo test dell'unità crea una falsa versione (falsa) di quel servizio casella messaggi che non mostra una finestra di messaggio

guarda a http://martinfowler.com/articles/injection.html per dettagli su IoC, il mio contenitore preferito è Ninject (http://ninject.org)

1

Idealmente, si desidera che il codice testato con Test unitari sia logico e non dell'interfaccia utente. Pertanto, la logica del test non dovrebbe in realtà visualizzare una finestra di messaggio. Se si desidera testare l'interfaccia utente, quindi suggerirei Coded UI Tests.

A giudicare dalla tua domanda, immagino che il tuo codice non dovrebbe utilizzare un MessageBox. Forse, invece, considera l'utilizzo di una callback o arbitraria Action o gli approcci menzionati da Luke McGregor e Sergey V.

1

"Test di unità", nel suo significato esatto, è una prova di comportamento atomico. Questo non è l'unico tipo di test basati sul codice che puoi fare per il tuo codice. Soprattutto per testare scenari più lunghi con finestre di dialogo "Sì/No", i test basati su codice su larga scala sono spesso più efficaci dei test unitari.

Tuttavia, per essere in grado di scrivere più facili, sarebbe bene non solo per creare un servizio speciale come è stato menzionato da Sergii, ma anche per rendere le sue chiamate asincrone:

public interface IDialogService 
{ 
    Task<bool> ShowYesNoMessageBox(...); 
    ... 
} 

Avvolgendo messageboxes in chiamate di servizio non asincrone e sdrammatele, per scenari più lunghi inizierete a contraddire il pattern "Arrange-Act-Assert" prevedendo l'azione dell'utente prima che ciò accada realmente (facendo "Arrange" invece di "Act"), che può causare numerosi problemi nei test, specialmente se i test vengono eseguiti utilizzando BDD/SpecFlow. Effettuare queste chiamate in modo asincrono consente di evitare tali problemi.Vedere il mio blog article per dettagli e esempi di test su larga scala con messagebox.