2009-06-01 17 views
14

Así que he realizado algunas pruebas unitarias y tengo experiencia en la escritura de pruebas, pero no he adoptado totalmente a TDD como herramienta de diseño.TDD: Por dónde empezar la primera prueba

Mi proyecto actual es volver a trabajar con un sistema existente que genera números de serie como parte del proceso de ensamblaje de la empresa. Comprendo el proceso actual y el flujo de trabajo debido a la observación del sistema existente. También tengo una lista de nuevos requisitos y cómo van a modificar el flujo de trabajo.

Siento que estoy listo para comenzar a escribir el programa y he decidido forzarme a hacer finalmente TDD desde el principio hasta el final.

Pero ahora no tengo ni idea de por dónde empezar. (También me pregunto si estoy engañando al proceso TDD porque ya tengo una idea del flujo del programa para el usuario).

El flujo de usuarios es realmente en serie y es solo una serie de pasos. A modo de ejemplo, el primer paso sería:

  • usuario envía un número de orden de fabricación y recibe una lista de números de parte serializables de ese proyecto de ley pedidos de materiales

El siguiente paso se inicia cuando el usuario selecciona uno de los números de parte.

Así que estaba pensando que puedo usar este primer paso como punto de partida. Sé que quiero un código que tome un número de pedido de fabricación y devuelva una lista de números de pieza.

// This isn't what I'd want my code to end up looking like 
// but it is the simplest statement of what I want 
IList<string> partNumbers = GetPartNumbersForMfgOrder(string mfgOrder); 

Reading Kent Becks libro de ejemplo que habla acerca de escoger pequeñas pruebas. Esto parece una caja negra bastante grande. Necesitará un repositorio de orden de mfg y tengo que rastrear un árbol de estructura de producto para encontrar todos los números de parte aplicables para este orden de fabricación y ni siquiera he definido el código de mi modelo de dominio en absoluto.

Por un lado, parece un comienzo horrible, una función muy general de alto nivel. Por otro lado, siento que si empiezo en un nivel inferior realmente solo estoy adivinando lo que podría necesitar y eso parece anti-TDD.


Como nota al margen ... ¿así es como usarías las historias?

Como un ensamblador Quiero obtener una lista de números de piezas en un orden MFG De modo que pueda elegir cuál va a serializar

A decir verdad, un ensamblador nunca diría eso. Todo un ensamblador quiere es terminar la operación el fin MFG:

Como un ensamblador que desea marcar piezas con un número de serie De modo que pueda terminar la operación en el orden MFG

Respuesta

15

Así es como comenzaría. Supongamos que no tiene absolutamente ningún código para esta aplicación.

  1. Definir la historia de usuario y el valor de negocio que trae: "Como Usuario Deseo someter un número de orden de fabricación y una lista de referencias de que las órdenes para que yo pueda enviar la lista al sistema de inventario "
  2. comienza con la interfaz de usuario. Cree una página muy simple (supongamos que es una aplicación web) con tres campos: etiqueta, lista y botón. Eso es suficiente, ¿no? El usuario podría copiar la lista y enviarla al sistema inv.
  3. Use un patrón para basar su diseño, como MVC.
  4. Define una prueba para el método de tu controlador que se llama desde la interfaz de usuario. Está probando aquí que el controlador funciona, no que los datos son correctos: Assert.AreSame(3, controller.RetrieveParts(mfgOrder).Count)
  5. Escriba una implementación simple del controlador para asegurarse de que se devuelve algo: return new List<MfgOrder>{new MfgOrder(), new MfgOrder(), new MfgOrder()}; También necesitará implementar clases para MfgOrder, por ejemplo .
  6. ¡Ahora su IU está funcionando! Trabajando incorrectamente, pero trabajando. Entonces, esperemos que el controlador obtenga los datos de un servicio o DAO. Cree un objeto DAO simulado en el caso de prueba y agregue la expectativa de que se llame al método "partsDao.GetPartsInMfgOrder()".
  7. Crea la clase DAO con el método. Llame al método desde el controlador. Su controlador ya está hecho.
  8. Cree una prueba por separado para probar el DAO, finalmente asegurándose de que devuelve los datos correctos del DB.
  9. Sigue iterando hasta que lo hayas hecho todo. Después de un tiempo, te acostumbrarás.

El punto principal aquí es separar la aplicación en partes muy pequeñas, y probar esas piezas pequeñas individualmente.

1

Creo que tienes un buen comienzo pero no lo veo del todo así. La prueba que se supone que genera más pruebas tiene mucho sentido para mí, como si lo pensara, ¿sabe ya qué número de pedido de fabricación o número de pieza tiene? Tienes que construir los que posiblemente te conduzcan a otras pruebas, pero eventualmente llegarás a las pruebas de poca monta que creo.

He aquí una historia que puede requerir un poco de romper:

  • Como Usuario Deseo someter un número de orden de fabricación y recibir una lista de números de parte serializables de ese proyecto de ley pedidos de materiales

Creo que la clave es dividir las cosas una y otra vez en pequeños pedazos que hacen que sea construir todo. Esa técnica de "Dividir y conquistar" es útil a veces. ;)

+0

Olvidaste la tercera parte de la historia, el beneficio. También tiene detalles de implementación allí, que no aportan ningún beneficio comercial (serializable). Diría que una historia mejor sería algo como "Como usuario, quiero enviar un número de pedido de fabricación y una lista de números de parte de esos pedidos para poder enviar la lista al sistema de inventario". –

+0

Serializable en ese contexto no es implementación, es un término de dominio que indica qué partes pueden llevar un número de serie, por lo que es importante (en la medida en que entiendo los requisitos). –

+0

Si ese es el caso, entonces tienes razón. La experiencia del dominio es todo. –

1

Pues bien, has llegado a la misma pared exacta que hice cuando traté TDD por primera vez :)

Desde entonces, me di por vencido en él, simplemente porque hace refactorización demasiado caro - y tiendo a refactorizar mucho durante la etapa inicial de desarrollo.

Con esas palabras malhumoradas fuera del camino, me parece que uno de los aspectos más controlados y más importantes de TDD es que te obliga a definir tus interfaces de clase antes de implementarlas realmente. Eso es algo muy bueno cuando necesita ensamblar todas sus piezas en un producto grande (bueno, en subproductos;)). Lo que debe hacer antes de escribir sus primeras pruebas, es tener su modelo de dominio, modelo de implementación y preferiblemente una buena parte de sus diagramas de clase listos antes de la codificación, simplemente porque necesita identificar sus invariantes, valores mínimos y máximos, etc. ., antes de que puedas probar para ellos. Debería poder identificarlos en un nivel de pruebas unitarias desde su diseño.

Soo, en mi experiencia (no en la experiencia de algún autor que disfruta analogías mapeo del mundo real para OO: P), TDD debe ir como esto:

  1. Crear el diagrama de despliegue, a partir de la especificación de requisitos (OFC, nada está escrito en piedra - nunca)
  2. Escoja una historia de usuario para implementar
  3. crear o modificar su modelo de dominio para incluir esta historia
  4. Crear o modificar su clase diagrama para incluir esta historia (incluyendo varios clases de diseño)
  5. Identificar vectores de prueba.
  6. Cree las pruebas según la interfaz que realizó en el paso 4
  7. Pruebe las pruebas (!). Este es un paso muy importante ..
  8. Implementar las clases
  9. prueba las clases
  10. ir a tomar una cerveza con sus :)
+5

No está haciendo el desarrollo Test DRIVEN si está haciendo esto. Está escribiendo pruebas, pero no deriva su diseño de los casos de prueba. –

+2

Sí, bueno, eso está en los ojos del espectador :) De la forma en que lo veo, no se puede derivar el 100% de su diseño de las causas de las pruebas. Al menos no de manera eficiente - imho.Las pruebas son para detalles de implementación, no para diseño. De nuevo, mi punto de vista personal. – cwap

4

compañeros de trabajo Esto está perfectamente bien como una prueba de partida. Con esto defines el comportamiento esperado: cómo debería funcionar. Ahora bien, si sientes que has tomado un bocado mucho más grande del que te hubiera gustado ... puedes ignorar temporalmente esta prueba y escribir una prueba más granular que elimine parte o al menos a mitad de camino. Luego, otras pruebas que lo llevarán a la meta de hacer pasar el primer gran examen. Red-Green-Refactor en cada paso.

Pruebas pequeñas, creo que significa que no deberías probar muchas cosas en una prueba. p.ej. Son los componentes D.A, B y C en state1, state2 y state3 después de haber llamado a Method1(), Method2() y Method3() con estos parámetros en D. Cada prueba debe probar solo una cosa. Puede buscar SO para las calidades de buenas pruebas.Pero me gustaría considerar la prueba para ser una pequeña prueba, ya que es corto y centrado en una tarea - 'Obtener Números de serie desde la fabricación Orden

actualización: Como A-Try sugerencia (AFAIR del libro de Beck), puede sentarse y elaborar una lista de pruebas de una línea para el SUT en un pedazo de papel. Ahora puede elegir la más fácil (pruebas que esté seguro de que podrá realizar) con el fin de generar confianza. O puede intentar uno con el 80% de confianza, pero tiene algunas áreas grises (también es mi elección) porque lo ayudará a aprender algo sobre el SUT en el camino. Mantenga los que no tiene idea de cómo proceder para el final ... con suerte, será más claro cuando se hagan los más fáciles. Golpéelos uno por uno a medida que se pongan verdes.

+0

Así que esto me tranquilizó y me senté a escribir la prueba. Incluso pensar en cómo escribirlo es una experiencia de diseño. No estoy seguro si estoy contento con mi examen, pero es un punto de partida y me hace pensar en algunas cosas. – anonymous

+0

Esta es precisamente la contribución más importante de TDD. Impulsa su diseño desde la perspectiva del cliente, lo que le obliga a agregar únicamente la funcionalidad que necesita al menos un cliente. Inicialmente, puede optar por falsificar colaboradores, pero eso aún le ayuda a identificar la interfaz más simple entre ellos, lo cual es una gran victoria. No es bueno tener o se puede requerir en las características futuras; Además, la refactorización continua ayuda a mantener su diseño simple, fácil de entender y, por lo tanto, fácil de mantener. – Gishu

+0

Volví y leí las primeras 40-50 páginas del libro de Beck y algunas cosas se hundieron un poco más desde mi última lectura (hace unos meses). Las dos cosas que están ayudando son a) puedes pecar para hacer un pase de prueba yb) inmediatamente refactorizas una vez en verde. Y sí, centrarme y pensar con respecto al SUT me está ayudando, especialmente al pensar en todos los contextos en los que podría existir el SUT; está conduciendo a pruebas más fuertes y menos frágiles. – anonymous

Cuestiones relacionadas