TL; DR
Escribir buenas y útiles pruebas es difícil y tiene un alto costo en C ++. ¿Pueden los desarrolladores experimentados compartir su razonamiento sobre qué y cuándo probar?
Larga historia
Solía hacer un desarrollo basado en pruebas, de hecho todo mi equipo, pero no funcionó bien para nosotros. Tenemos muchas pruebas, pero nunca parecen cubrir los casos en que tenemos errores y regresiones reales, que generalmente ocurren cuando las unidades interactúan, no por su comportamiento aislado.
Esto es a menudo tan difícil de probar en el nivel de la unidad que dejamos de hacer TDD (a excepción de los componentes donde realmente acelera el desarrollo), y en cambio invertimos más tiempo aumentando la cobertura de la prueba de integración. Si bien las pruebas de unidades pequeñas nunca detectaron ningún error real y fueron básicamente solo gastos generales de mantenimiento, las pruebas de integración realmente han valido la pena.
Ahora heredé un nuevo proyecto y me pregunto cómo probarlo. Es una aplicación nativa de C ++ / OpenGL, por lo que las pruebas de integración no son realmente una opción. Pero las pruebas unitarias en C ++ son un poco más difíciles que en Java (tienes que hacer cosas explícitamente virtual
), y el programa no está muy orientado a objetos, por lo que no puedo burlarme de algunas cosas.
No quiero destrozar y OO-ize todo el asunto solo para escribir algunas pruebas en aras de escribir pruebas. Entonces te pregunto: ¿para qué debo escribir las pruebas? p.ej:
- ¿Funciones / clases que espero cambiar con frecuencia?
- ¿Funciones / clases que son más difíciles de probar manualmente?
- ¿Funciones / clases que ya son fáciles de probar?
Comencé a investigar algunas bases de código respetuosas de C ++ para ver cómo funcionan las pruebas. En este momento estoy investigando el código fuente de Chromium, pero me resulta difícil extraer su lógica de prueba del código. Si alguien tiene un buen ejemplo o una publicación sobre cómo los usuarios populares de C ++ (chicos del comité, autores de libros, Google, Facebook, Microsoft, ...) abordan esto, sería de gran ayuda.
Actualizar
He buscado en este sitio y en la web desde que escribí esto. Encontré algunas cosas buenas:
- ¿Cuándo es apropiado no realizar pruebas unitarias?
- /programming/109432/what-not-to-test-when-it-comes-to-unit-testing
- http://junit.sourceforge.net/doc/faq/faq.htm#best
Lamentablemente, todos estos son más bien centrados en Java / C #. Escribir muchas pruebas en Java / C # no es un gran problema, por lo que el beneficio generalmente supera los costos.
Pero como escribí anteriormente, es más difícil en C ++. Especialmente si su código base no es tan OO, tiene que estropear gravemente las cosas para obtener una buena cobertura de prueba de unidad. Por ejemplo: la aplicación que heredé tiene un Graphics
espacio de nombre que es una capa delgada sobre OpenGL. Para probar cualquiera de las entidades, que usan sus funciones directamente, tendría que convertir esto en una interfaz y una clase e inyectarlo en todas las entidades. Ese es solo un ejemplo.
Entonces, al responder esta pregunta, tenga en cuenta que tengo que hacer una inversión bastante grande para escribir pruebas.
fuente
Respuestas:
Bueno, las pruebas unitarias son solo una parte. Las pruebas de integración lo ayudan con el problema de su equipo. Las pruebas de integración se pueden escribir para todo tipo de aplicaciones, también para aplicaciones nativas y OpenGL. Debe consultar "Crecimiento de software orientado a objetos guiado por pruebas" por Steve Freemann y Nat Pryce (por ejemplo, http://www.amazon.com/Growing-Object-Oriented-Software-Guided-Signature/dp/0321503627 ). Le guía paso a paso a través del desarrollo de una aplicación con GUI y comunicación de red.
Las pruebas de software que no se probaron son otra historia. Consulte Michael Feathers "Trabajando eficazmente con código heredado" (http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052).
fuente
Es una pena que TDD "no funcionó bien para usted". Creo que esa es la clave para entender hacia dónde acudir. Revise y comprenda cómo TDD no funcionó, qué podría haber hecho mejor, por qué hubo dificultades.
Entonces, por supuesto, sus pruebas unitarias no detectaron los errores que encontró. Ese es el tipo de punto. :-) No encontró esos errores porque evitó que ocurrieran en primer lugar al pensar cómo deberían funcionar las interfaces y cómo asegurarse de que se probaron correctamente.
Para responder, usted pregunta, como ha concluido, el código de prueba de unidad que no está diseñado para ser probado es difícil. Para el código existente, puede ser más efectivo usar un entorno de prueba funcional o de integración en lugar de un entorno de prueba unitaria. Pruebe el sistema en general enfocándose en áreas específicas.
Por supuesto, el nuevo desarrollo se beneficiará de TDD. A medida que se agregan nuevas características, la refactorización para TDD podría ayudar a probar el nuevo desarrollo, al tiempo que permite el desarrollo de nuevas pruebas unitarias para las funciones heredadas.
fuente
No he hecho TDD en C ++, así que no puedo comentar sobre eso, pero se supone que debes probar el comportamiento esperado de tu código. Si bien la implementación puede cambiar, el comportamiento debería (¿generalmente?) Permanecer igual. En el mundo centrado en Java \ C #, eso significaría que solo prueba los métodos públicos, escribe pruebas para el comportamiento esperado y lo hace antes de la implementación (que generalmente es mejor decirlo que hacerlo :)).
fuente