2011-12-19 12 views
8

Estoy tratando de encontrar la mejor manera de desacoplar messageboxes de mi lógica para que pueda probarlos correctamente. Ahora me preguntaba si sería suficiente si solo hiciera una clase de ayuda separada (C#) que puedo guardar más tarde para mi messagebox. Por ejemplo:Messagebox y prueba de unidad

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

A continuación, cada vez que había necesidad de utilizar un cuadro de mensaje que acababa de uso messageboxHelper/msgBoxAlg (...) en lugar de messagebox.show (...). Usando el bool show podría habilitarlo o deshabilitarlo durante la prueba.

Me pregunto si esta es la "manera correcta". Con lo que quiero decir, ¿hay una manera más fácil o mejor de hacer esto correctamente? No puedo abandonar las cajas de mensajes, sino que transmiten información "vital" al usuario ("¿Desea cerrar esta ventana?" SÍ/NO, etc.). También podría ser que no estoy utilizando la ingeniería de software adecuada, y ¿debería desacoplar mis messageboxes de mi businesslogic más?

Respuesta

29

Sí, es correcto. Pero en lugar de clase estática, se debe implementar IDialogService e inyectarla en las clases que se deben mostrar los cuadros de diálogo:

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

Durante las pruebas, el SomeClass, debe inyectarse objeto de burla de la IDialogService en lugar de uno real.

Si necesita probar más lógica de IU, considere utilizar el patrón MVVM.

+0

¡Gracias, explicación muy clara! –

+0

¡Me encanta el término "IDialogService" como una abstracción! – Samuel

2

Mire en Inversión de control (IoC), el principio básico es que las cosas que realizan acciones ect deben pasarse como una interfaz y luego usar un contenedor IoC para enlazar interfaces a implementaciones específicas para su aplicación. Para lograr esto fácilmente en su caso pase lo que hace cuadros de mensaje en una interfaz y en su prueba de unidad crea una versión simulada (falsa) de ese mensaje que no muestra un cuadro de mensaje

para http://martinfowler.com/articles/injection.html para detalles sobre IoC, mi contenedor favorito es Ninject (http://ninject.org)

1

Idealmente, desea que el código de su prueba con las pruebas unitarias sea lógica y no de interfaz de usuario. Por lo tanto, la lógica de su prueba no debería realmente mostrar un cuadro de mensaje. Si quieres probar la interfaz de usuario, entonces sugeriría Coded UI Tests.

A juzgar por su pregunta, me imagino que su código no debería estar realmente usando un MessageBox. Tal vez, en cambio, considere usar una devolución de llamada o arbitraria Action, o los enfoques mencionados por Luke McGregor y Sergey V.

1

"Prueba de unidad", en su significado exacto, es una prueba de comportamiento atómico. Este no es el único tipo de pruebas controladas por código que puede realizar para su código. Especialmente para probar escenarios más largos con los diálogos "Sí/No" que menciona, las pruebas controladas por código a gran escala suelen ser más efectivas que las pruebas unitarias.

Sin embargo, para ser capaz de escribir más fácil, sería bueno no sólo para crear un servicio especial, ya que fue mencionado por Sergii, sino también para hacer sus llamadas asíncronas:

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

Al envolver los cuadros de mensajes en llamadas de servicio no asincrónicas y burlándose de ellas, para escenarios más largos comenzará a contradecir el patrón "Arrange-Act-Assert" al predecir la acción del usuario antes de que realmente ocurra (haciendo "Arrange" en lugar de "Act"), lo que puede causar numerosos problemas en las pruebas, especialmente si sus pruebas se realizan utilizando BDD/SpecFlow. Hacer estas llamadas asíncronas permite evitar tales problemas.Consulte mi blog article para obtener detalles y ejemplos de pruebas a mayor escala con messageboxes.