2009-09-26 20 views
7

Estoy escribiendo una aplicación similar a TotalCommander. Tengo un componente separado para la lista de archivos y un modelo para él. oyentes de apoyo modelo y emite una notificación de eventos como CurrentDirChanged etc. en forma siguiente:Prueba de unidades de un componente Swing

 
private void fireCurrentDirectoryChanged(final IFile dir) { 
    if (SwingUtilities.isEventDispatchThread()) 
     for (FileTableEventsListener listener : tableListeners) 
      listener.currentDirectoryChanged(dir); 
    else { 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       for (FileTableEventsListener listener : tableListeners) 
        listener.currentDirectoryChanged(dir); 
      } 
     }); 
    } 
} 

He escrito una prueba simple para esto:

 
@Test 
public void testEvents() throws IOException { 
    IFile testDir = mockDirectoryStructure(); 
    final FileSystemEventsListener listener = 
       context.mock(FileSystemEventsListener.class); 
    context.checking(new Expectations() {{ 
     oneOf(listener).currentDirectoryChanged(with(any(IFile.class))); 
    }}); 

    FileTableModel model = new FileTableModel(testDir); 
    model.switchToInnerDirectory(1); 
} 

esto no funciona, porque no hay EventDispatchThread. ¿Hay alguna forma de probar esta unidad dentro de la construcción sin cabeza?

-prueba de la unidad java swing de JMock

Respuesta

10

Nota, en términos generales las pruebas unitarias en materia de interfaz de usuario es siempre difícil porque hay que burlarse de un montón de cosas que es simplemente no está disponible.
Por lo tanto, el objetivo principal al desarrollar aplicaciones (de cualquier tipo) es siempre tratar de separar todo lo de la interfaz de usuario de la lógica principal de la aplicación tanto como sea posible. Tener fuertes dependencias aquí, hace que las pruebas unitarias sean realmente difíciles, una pesadilla básicamente. Esto generalmente se aprovecha mediante el uso de patrones como un tipo de enfoque MVC, donde prueba principalmente las clases de controlador y las clases de vista no hacen nada más que construir la interfaz de usuario y delegar sus acciones y eventos a los controladores. Esto separa las responsabilidades y facilita las pruebas.

Además, no debe necesariamente probar cosas que ya están provistas por el framework, como probar si los eventos se dispararon correctamente. Debería probar la lógica que está escribiendo usted mismo.

+1

Escribí este código y quiero probar que dispara eventos cuando debería y con los parámetros correctos.Supongo que lo que estoy haciendo mal aquí es asegurar el hilo de GUI dentro de un modelo. El modelo no es un componente Swing, no tiene que activar eventos dentro de un hilo GUI. ¿Estoy pensando correctamente aquí? –

12

Look this:

FEST es una colección de bibliotecas, publicado bajo la Apache 2.0 license, cuya misión es simplificar las pruebas de software. Se compone de varios módulos, que se pueden utilizar con o TestNGJUnit ...

+0

Parece interesante. –

+0

Lamento no aceptar su respuesta, pero realmente no quiero probar la GUI, solo quiero probar mi modelo sin problemas. –

2

Comprobar el proyecto uispec4j. Eso es lo que uso para probar mis UI.

www.uispec4j.org

+0

parece un ....... proyecto difunto? (el enlace ya no parece ir a donde fue antes) – Snappawapa

1

Sólo he estado trabajando con jMock durante dos días ... así que por favor discúlpeme si hay una solución más elegante. :)

Parece que su FileTableModel depende de SwingUtilities ... ¿Ha considerado burlarse de las SwingUtilities que utiliza? Una forma que huele a hack pero que resolvería el problema sería crear una interfaz, digamos ISwingUtilities, e implementar una clase ficticia MySwingUtilities que simplemente reenvía a las SwingUtilities reales. Y luego en su caso de prueba puede simular la interfaz y devolver true para isEventDispatchThread.

@Test 
public void testEventsNow() throws IOException { 
    IFile testDir = mockDirectoryStructure(); 

    final ISwingUtilities swingUtils = context.mock(ISwingUtilities.class); 

    final FileSystemEventsListener listener = 
       context.mock(FileSystemEventsListener.class); 

    context.checking(new Expectations() 
    {{ 
     oneOf(swingUtils).isEventDispatchThread(); 
      will(returnValue(true)); 

     oneOf(listener).currentDirectoryChanged(with(any(IFile.class))); 
    }}); 

    FileTableModel model = new FileTableModel(testDir); 
    model.setSwingUtilities(swingUtils); // or use constructor injection if you prefer 
    model.switchToInnerDirectory(1); 
} 
+0

Esto es básicamente cómo lo hacemos. Reemplazamos SwingUtilities con OurSwingUtilities.getInstance() y luego en las pruebas, tenemos una implementación alternativa (no usamos jMock para ello, porque muchas pruebas pueden compartir más convenientemente una sola clase). Hacemos esto para SwingWorker.execute() así como una gran cantidad de utilidades que son estáticas en la biblioteca de Java. – Trejkaz

2

Creo que el problema con las pruebas está revelando un problema con el código. No debería ser realmente el trabajo del modelo decidir si se está ejecutando en el hilo de envío, eso es demasiadas responsabilidades. Simplemente debe hacer su trabajo de notificación y dejar que un componente llamante decida si llamarlo directamente o invocarLater. Ese componente debe estar en la parte del código que conoce acerca de los hilos Swing. Este componente solo debe conocer los archivos y tal.

Cuestiones relacionadas