2011-11-02 18 views
5

He leído toneladas de artículos, he visto toneladas de screencasts sobre TDD, pero todavía estoy luchando con su uso en proyectos del mundo real. Mi problema principal es que no sé por dónde empezar, qué prueba debería ser la primera. Supongamos que tengo que escribir la biblioteca del cliente llamando a los métodos del sistema externo (por ejemplo, notificación). Quiero que este cliente para que funcione de la siguiente manera¿Cómo elegir el punto de partida de TDD en un proyecto del mundo real?

NotificationClient client = new NotificationClient("abcd1234"); // client ID 
Response code = client.notifyOnEvent(Event.LIMIT_REACHED, 100); // some params of call 

Existe cierta traducción y preparación mensaje formato detrás de las escenas, así que me gustaría para ocultarlo de mis aplicaciones cliente.

No sé dónde y cómo comenzar. ¿Debo hacer algunas clases aproximadas para esta biblioteca? ¿Debo comenzar con las pruebas de la siguiente manera NotificationClient

public void testClientSendInvalidEventCommand() { 
    NotificationClient client = new NotificationClient(...); 
    Response code = client.notifyOnEvent(Event.WRONG_EVENT); 
    assertEquals(1223, code.codeValue()); 
} 

Si es así, la prueba de este tipo que estoy obligado a escribir la implementación completa de trabajo a la vez, sin pasos de bebé como estados TDD. Puedo burlarme de sosmething en Client pero luego tengo que saber esto para burlarme por adelantado, así que necesito un poco de preparación inicial para ser hecho.

Tal vez debería comenzar desde la parte inferior, probar este componente de formato de mensaje primero y luego usarlo en la prueba de cliente correcta?

¿De qué manera es la correcta para llevar? ¿Deberíamos siempre comenzar desde arriba (cómo lidiar con este gran paso requerido)? ¿Podemos comenzar con cualquier clase realizando una pequeña parte de la función deseada (como formateador en este ejemplo)?

Si tuviera que saber dónde golpear con mis pruebas, sería mucho más fácil para mí proceder.

Respuesta

1

No confunda acceptance tests que enganche en cada extremo de su aplicación, y forme un executable specifications con unit tests.

Si está haciendo TDD 'puro', escriba una prueba de aceptación que impulse las pruebas unitarias que impulsan la implementación. testClientSendInvalidEventCommand es su prueba de aceptación, pero dependiendo de cuán complicadas sean las cosas, delegará la implementación en múltiples clases que puede probar por separado.

Cuan complicadas son las cosas antes de que tenga que dividirlas para probarlas y entenderlas correctamente es por eso que se llama Test Driven Diseño.

+0

¿Pero cómo encontrar esas clases para escribir las pruebas unitarias y por dónde empezar? Supongo que necesito tener algunas clases configuradas para poder elegir el punto de partida para TDD. Pero entonces, ¿dónde debería estar este punto? ¿Debería estar en los bordes del sistema, o puede estar en el medio del sistema, como se mencionó en el formato? –

+0

Puede TDD ascendente o descendente. No veo cómo el formateador se ajusta a tu ejemplo. Con una prueba, debe escribir la cantidad de código ** mínima ** necesaria para que pase. –

0

Uno de los objetivos de TDD es que las pruebas informen el diseño. Entonces, el hecho de que necesite pensar cómo implementar su NotificationClient es algo bueno; te obliga a pensar en (con suerte) simples abstracciones por adelantado.

Además, TDD supone una refacturación constante. Tu primera solución probablemente no será la última; a medida que refina su código, las pruebas están ahí para decirle qué se rompe, desde errores de compilación hasta problemas reales de tiempo de ejecución.

Así que me gustaría ir directamente y comenzar con la prueba que sugirió. Al crear burlas, deberá crear pruebas para las implementaciones reales de lo que se burla. Encontrará que las cosas tienen sentido y es necesario cambiarlas, por lo que tendrá que modificar sus pruebas sobre la marcha. Así se supone que debe funcionar ...

+0

Bien, supongamos que identifiqué dos colaboradores aquí: formateador para crear mensajes en el formato requerido y ConnectionHandler para manejar las conexiones y enviar mensajes de bajo nivel. ¿Es suficiente para comenzar a probar? ¿Por dónde empezar entonces? ¿Con pruebas ConnectionHandler, o Formatter? O tal vez el cliente con esos dos deps burlados? –

+0

Solo elija uno u otro - Creo que está en parálisis de análisis - solo hágalo y se resolverá solo ... – hvgotcodes

1

Puede optar por permitir que las pruebas dirijan su diseño de abajo hacia arriba o de arriba hacia abajo. Ambos funcionan bien para diferentes desarrolladores en diferentes situaciones.Cualquier enfoque obligará a tomar algunas de esas decisiones de diseño "iniciales", pero eso es algo bueno. ¡Tomar esas decisiones para escribir tus pruebas es un diseño basado en pruebas!

En su caso, usted tiene una idea de cuál es la interfaz externa de alto nivel para el sistema que está desarrollando, así que comencemos allí. Escriba una prueba de cómo cree que los usuarios de su cliente de notificación deberían interactuar con ella y dejar que falle. Esta prueba es la base de sus pruebas de aceptación o integración y continuarán fallando hasta que se terminen las características que describen. Está bien. Ahora baja un nivel. ¿Cuáles son los pasos que deben darse para proporcionar esa interfaz de alto nivel? ¿Podemos escribir una prueba de integración o unidad para esos pasos? ¿Tienen dependencias que no había considerado que podrían hacer que cambie la interfaz del centro de notificación que ha comenzado a definir? Siga profundizando en el comportamiento de definición de profundidad con pruebas fallidas hasta que encuentre que realmente ha llegado a una prueba de unidad. Ahora implemente lo suficiente para pasar esa prueba unitaria y continuar. Haga pasar las pruebas unitarias hasta que haya construido lo suficiente como para pasar una prueba de integración, y así sucesivamente. Eventualmente habrá completado una construcción en profundidad de un árbol de pruebas y debería tener una función bien probada cuyo diseño fue impulsado por sus pruebas.

2

me gustaría empezar con esta línea:

NotificationClient client = new NotificationClient("abcd1234"); // client ID 

Suena como necesitamos un NotificationClient, que necesita un ID de cliente. Eso es algo fácil de probar. Mi primera prueba podría ser algo como:

public void testNewClientAbcd1234HasClientId() { 
    NotificationClient client = new NotificationClient("abcd1234"); 
    assertEquals("abcd1234", client.clientId()); 
} 

Por supuesto, no se compilará en un primer momento - no hasta que había escrito una clase NotificationClient con un constructor que toma un parámetro de cadena y una clientId método() que devuelve una cadena, pero eso es parte del ciclo TDD.

public class NotificationClient { 
    public NotificationClient(string clientId) { 
    } 
    public string clientId() { 
     return ""; 
    } 
} 

En este punto, puedo correr mi prueba y ver que falle (porque he clientId no modificable() 's vuelta a ser una cadena vacía). Una vez que tengo mi prueba de la unidad en su defecto, escribo lo suficiente código de producción (en NotificationClient) para obtener la prueba de pasar:

public string clientId() { 
     return "abcd1234"; 
    } 

Ahora pasan todas mis pruebas, para que pueda considerar qué hacer a continuación. La obvia (bueno, obvio para mí ) siguiente paso es asegurarse de que puedo crear clientes cuya identificación no es "abcd1234":

public void testNewClientBcde2345HasClientId() { 
    NotificationClient client = new NotificationClient("bcde2345"); 
    assertEquals("bcde2345", client.clientId()); 
} 

dirigir mi banco de pruebas y observo que testNewClientBcde2345HasClientId() falla mientras testNewClientAbcd1234HasClientId() pasa, y ahora tengo una buena razón para agregar una variable miembro a NotificationClient:

public class NotificationClient { 
    private string _clientId; 
    public NotificationClient(string clientId) { 
     _clientId = clientId; 
    } 
    public string clientId() { 
     return _clientId; 
    } 
} 

Suponiendo que no hay errores tipográficos han colado, que ponerlas todas mis pruebas a pasar, y yo puede pasar al siguiente paso. (En su ejemplo, probablemente estaría probando que notifyOnEvent(Event.WRONG_EVENT) devuelve Response cuyo codeValue() es igual a 1223.)

¿Eso ayuda?

Cuestiones relacionadas