unit testing - practice - Comenzando un proyecto TDD desde cero
tdd practice exercises (4)
Comience de manera simple, agregará funciones de manera gradual más adelante. Comience desde un diseño rápido: qué clases, qué responsabilidades, qué relaciones. Puede utilizar tarjetas CRC . No dedique demasiado tiempo a ese diseño, ya que podrá mejorarlo más tarde mediante la refactorización. Elija la clase más simple para comenzar con la implementación de una capacidad simple del sistema. Por ejemplo, primero puedes crear una página vacía.
Comenzar con una clase? ¿Qué harán sus objetos? ¿Cómo puedes verificar que esto se haga correctamente? Esta es la primera prueba.
También puede comenzar sin la base de datos y almacenar sus documentos en un archivo plano. Se refactorizará a una base de datos más tarde. Luego puedes comenzar con la función getAllDocuments ().
Leí muchas preguntas y respuestas en TDD y pruebas de unidad en SO, pero no encontré nada que respondiera a eso: ¿de dónde empiezo?
El equipo y yo ya hicimos un par de proyectos en los que adoptamos el uso de pruebas de unidad para nuestro código ... pero primero codificamos y luego pruebas de unidad. En algún momento del proceso de desarrollo, se volvió bastante natural escribir primero la prueba y luego el código, lo que nos lleva a un estilo más TDD.
Ahora nos gustaría dar el siguiente paso e intentar comenzar un nuevo proyecto con TDD desde el principio. Aquí está el problema ... ¿por dónde empezar? ¿Cuál es la primera prueba que escribiría cuando no tengo ningún código?
Digamos, solo para tener un contexto en el que pensar, que tengo que desarrollar una aplicación de Internet, centrada en el documento, con un poco de flujo de trabajo y ... algo más. Pero empecemos por el principio: primero, quiero crear una página simple que enumere todos los documentos (metadatos) almacenados en una tabla en una base de datos (bastante simple, ¿eh?). ¿Cuál es la primera prueba que escribiría? Digamos que estoy usando Hibernate para acceder a la base de datos ... ¿probaría el método ipothetical getAllDocuments ()? ¿Pero debo usar un objeto simulado para sustituir a Hibernate? Entonces, ¿qué estoy probando?
Estoy un poco confundido aquí ... además, los GetAlDocuments () probablemente nunca serán un método de producción ... toda la colección de documentos será ordenada y filtrada por algo ... ¿tiene sentido? Cualquier sugerencia será apreciada
Editado:
Después de leer sus respuestas (y el hilo similar en http://programmers.stackexchange.com ) vengo con una mejor visión de TDD, pero todavía tengo un duda.
Siempre pensé que TDD es hacer la prueba de unidad primero ... nunca pensé en la prueba de extremo a extremo. Pero déjeme preguntar: TDD dice que tiene que escribir una prueba y ver un error de compilación; luego creas clase y método y obtienes un fallo de prueba; Luego implementas el método y obtienes la prueba. No puede escribir código hasta que haya una prueba que falle; no puedes escribir otra prueba hasta que todas las pruebas pasen. Estoy aquí?
¿Cómo puedo hacer una prueba integral como mi primera prueba? Debería escribir todo el código, en toda la capa, para dejar pasar la prueba. Pero luego tendré un montón de clases y métodos todos probados por mi prueba de extremo a extremo (¿no debería llamarlo prueba de integración?). Esto significa que ya no necesitaré una prueba de unidad, porque ya tengo una prueba que cubre mi código. Y no puedo escribir una prueba que ya haya pasado, es contra la práctica de TDD.
Ayúdame a entender este paso más adelante por favor
Normalmente comienzo de arriba a abajo. En su caso, comenzaría escribiendo la lógica del controlador de su nueva página. Por controlador me refiero a la capa de código justo debajo de la interfaz de usuario, burlándose de todo lo que está debajo. Luego escriba la capa de servicio (si tiene una), burlándose de la capa de datos. Finalmente, pruebe la capa de datos también con simulacros de las clases subyacentes (podría ser ISession en su caso). Finalmente, escribiría una sola prueba de integración de cada uno de los métodos de capa de datos y compilaría la página (html).
TDD no se trata de pruebas unitarias: TDD se trata de impulsar su desarrollo y arquitectura con pruebas, con cualquier tipo de pruebas automatizadas que necesite. ¿Ves el punto?
Está comenzando un nuevo proyecto y probablemente tenga un conjunto de características. Debe tener algunos criterios de aceptación para las características que va a implementar. Estos criterios pueden definir sus pruebas de nivel superior. Comencemos con una prueba de extremo a extremo (esto puede ser bastante difícil a veces porque involucra una IU que aún no existe) o una prueba de integración para estos criterios de aceptación. Una vez que tenga una prueba que está fallando, continuará implementando funciones relacionadas con la prueba grande, pero cada una de estas funciones será activada nuevamente con una prueba de integración o una prueba de unidad. La función se completa si todas las pruebas de nivel superior pasan.
Si omite pruebas grandes (de extremo a extremo, integración), desarrollará un conjunto de unidades bien probadas que no funcionarán cuando se integren juntas o su arquitectura no será muy buena debido al alcance local definido por las pruebas unitarias. Las pruebas de integración y de extremo a extremo le brindan un alcance global.
Esto se describe con un gran ejemplo (Java) en el libro Software orientado a objetos en crecimiento guiado por pruebas .
Ya que está intentando impulsar el desarrollo basado en las pruebas, la forma de comenzar es comenzar con su primera función. Por ejemplo, supongamos que tiene una función para cargar documentos. Su primera prueba puede ser:
public class DocumentManagementTest {
@Test public void allowsDocumentUploads() {
DocumentManagement dm = new DocumentManagement();
Reader mockReader = new MockDocumentReader();
Document result = dm.createDocument("Document name", mockReader);
assertEquals("Document name", result.getName());
assertEquals(0, result.getTags().size());
assertTrue(mockReader.fileWasRead);
}
}
Definitivamente me gustaría burlarme de la base de datos, la configuración y el desmontaje de la base de datos es costoso y quebradizo. Sin embargo, recuerde que para realizar pasos muy pequeños, la prueba que mostré anteriormente probablemente habría evolucionado en unas pocas iteraciones. Las pruebas de seguimiento que eliminan más el diseño pueden ser:
@Test public void allowsDocumentRenames() { ... }
@Test public void allowsAddingTagsToExistingDocuments() { ... }
@Test public void showsErrorWhenAddingDocumentThatAlreadyExists() { ... }
Una vez que haya creado una característica como createDocument, puede crear un controlador a su alrededor.
public void doPost(HttpServletRequest req, HttpServletResponse resp) {
String name = req.getParameter("doc_name");
Document d = docMgmt.createDocument(name, req.getInputStream());
// Hand the newly created document to the view engine.
}
No me preocuparía demasiado la escritura de pruebas para el controlador, ya que es un riesgo bastante bajo desde un punto de vista de complejidad (si el controlador obtiene demasiado código, entonces puede oler que el código del controlador pertenece a otra clase, posiblemente su clase DocumentManagement ).
Al desarrollar la funcionalidad una característica a la vez y seguir los principios de SOLID, crecerá lentamente un sistema con una gran cobertura de prueba y propiedades OO bastante buenas.
¡Aclamaciones!
Brandon