2012-08-17 7 views
7

Estoy leyendo Clean Code: A Handbook of Agile Software Craftsmanship y uno de los ejemplos implica una clase Portfolio y una clase TokyoStockExchange. Sin embargo, Portfolio no es muy comprobable porque depende de TokyoStockExchange como una API externa para determinar el valor de la cartera y tal es una búsqueda bastante volátil y no propicia para las pruebas.Confundido acerca de por qué es útil para probar los objetos ficticios

Por lo tanto, resuelven esto creando una interfaz StockExchange común y tienen TokyoStockExchange y DummyStockExchange ambos implementan la clase base. Por lo tanto, se logra el principio de inversión de dependencia y en la clase PortfolioTest se puede crear una instancia de DummyStockExchange, fijar un precio de stock en una corporación, asignar la instancia DummyStockExchange a la cartera y agregar algunas acciones de esa compañía a la cartera y luego confirmar si el el valor esperado es de hecho el valor adecuado. Aquí está el código:

public class PortfolioTest 
{ 
    private DummyStockExchange exchange; 
    private Portfolio portfolio; 

    protected void setUp() 
    { 
     exchange = new DummyStockExchange(); 
     exchange.fix("MSFT", 100); 
     portfolio = new Portfolio(exchange); 
    } 

    public void GivenFiveMSFTTotalShouldBe500() 
    { 
     portfolio.add(5, "MSFT"); 
     Assert.assertEquals(500, portfolio.value()); 
    } 
} 

Mi pregunta, simplemente, es la razón por ?

Intentamos probar si la clase TokyoStockExchange funcionaba en conjunto con la clase Portfolio. Obviamente, si creamos otra clase con un nuevo método que establece un precio de acciones y le damos a la cartera cinco de esas acciones, todo funcionará. Simplemente parece ... inútil probarlo. Entiendo que TokyoStockExchange es básicamente imposible de probar con Portfolio debido a los cambios en los precios de las acciones, pero no entiendo cómo sustituir en una prueba más bien inútil ayuda a la situación.

Parece como si no supiéramos si nuestros programas de sumadores funcionan pero los únicos números disponibles se generan de forma aleatoria, por lo que creamos una clase ficticia que nos da 2 y probamos 2 + 2 = 4. Bueno, sí, obviamente eso es verdad. Todavía podemos romper TokyoStockExchange y la prueba seguirá teniendo éxito porque está probando otra clase. En todo caso, todo esto parece engañoso y también resulta en tener que escribir código adicional solo para probar algo que sabemos que va a funcionar.

Creo que este es el problema más grande que tengo con la comprensión de la Unidad de Pruebas en este momento. Sé que estoy equivocado, creo que no pude ver la luz. Espero que alguien pueda ayudarme.

+0

Como referencia ... si está probando que 'TokyoStockExchange' funciona * con *' Portfolio', se encuentra fuera del alcance de las pruebas unitarias. 'Portfolio' y' TokyoStockExchange' son unidades, y las pruebas unitarias están destinadas a probar cada * unidad * por separado de tantas otras como sea posible (preferiblemente todas). La interacción entre ellos es lo que * pruebas de integración * cubren. – cHao

+2

+1 para tratar de comprender el valor en lugar de deshacerse de las pruebas unitarias con "es más trabajo mantener ese código también" –

+0

Esto es realmente más una pregunta para [programadores.se]. –

Respuesta

7

La idea es que desee probar la lógica en la clase Portfolio aisladamente de TokyoStockExchange. Si utiliza un marco simulado como Moq o Rhino Mocks, puede simular fácilmente diferentes salidas y comportamientos desde TokyoStockExchange y escribir pruebas de unidad para asegurarse de que Portfolio responda correctamente. Debería escribir pruebas unitarias separadas para la clase TokyoStockExchange.

Esto no quiere decir que no necesite integración probando entre las dos clases. Es difícil verificar correctamente todos los escenarios sin el uso de objetos falsos.

Es difícil entender el valor con una clase tan simple como un ejemplo, pero dada una clase más compleja donde necesita verificar casos de prueba para situaciones difíciles o imposibles de organizar en una clase "en vivo", unidad las pruebas se vuelven mucho más importantes.

+3

+1 Exactamente. No está probando el TokyoStockExchange, está probando que la clase Portfolio funciona correctamente. – CaffGeek

+0

Para agregar: Desea realizar la prueba de forma aislada, de modo que cuando una prueba falla, es más fácil encontrar la causa raíz. Si ejecuta una prueba de integración con 20 clases diferentes en juego y "falla", puede pasar mucho tiempo buscando en las 20 clases la causa raíz. Si rescatas un grupo (como 19) y reduces la granularidad a una clase, reduces drásticamente el área de superficie que tienes que buscar/corregir. –

+0

Además, al crear una ** dependencia ** absoluta y conocida, elimina ** la variabilidad ** de la pregunta de la prueba. Esto crea una línea de base desde la que puede decir "Este objeto funciona exactamente como se esperaba cuando se le da una entrada estándar o esperada". Considere, en cambio, que la dependencia crea una conexión de base de datos, pero esa conexión falla por alguna razón ... no desea que esta prueba falle porque eso no es representativo de lo que está probando. –

3

Hay dos tipos de pruebas que debe realizar, pruebas unitarias y pruebas de integración.

Se supone que una prueba de unidad es una prueba de caja blanca donde se prueban todas las unidades de código de forma aislada. En general, esto se refiere a sus interfaces públicas en cada clase.Usted simula sus dependencias para que tenga la certeza de que, dado un conjunto conocido de datos, su unidad obtendrá resultados predecibles.

Usted dice, "obviamente, todo va a funcionar" en la prueba unitaria. Eso presupone que no tienes ningún error en tu código. ¡Si pudieras hacer esa suposición, no necesitarías probar nada en primer lugar! Y realmente no necesita probarlo todo; si su Portfolio es solo una capa delgada en la parte superior de su StockExchange que llama a los métodos de la API y transmite los resultados, no debe molestarse en probar la unidad.

Por otro lado, si su Portfolio tiene una lógica real, querría probarlo en una unidad. Digamos que Portfolio tiene un método para extraer datos del Stock Exchange, analizar los datos y enviar un mensaje de alerta a un usuario cuando el precio de la acción muestra alguna anomalía, como si el precio comienza a caer rápidamente. Te recomendamos que te asegures de que la alerta se activará en las condiciones previstas, pero no querrás sentarte y esperar a que la próxima bolsa se cierre. Por lo tanto, en su prueba de unidad, haría una simulación Stock Exchange que produce los tipos de valores que desea activar la alerta, y luego verifica que realmente suceda. Si lo hace, genial, si no, acabas de encontrar un error.

Las pruebas de integración probarán las dos unidades en tándem, y también es importante. Pero es más difícil simular ciertos tipos de escenarios en las pruebas de integración, y es menos útil para descubrir dónde se esconde realmente un error. Si ejecutó una prueba de integración para su aplicación y descubrió que no estaba enviando alertas cuando debería, ¿dónde está el problema? ¿Hay algún error en la API de terceros? ¿La bolsa le envía malos valores? ¿Su sistema de alerta está enviando mensajes a la dirección incorrecta? Puede tomar un tiempo para que descubras que hubo un problema con tu método de análisis.

Cuestiones relacionadas