Actualmente en mi trabajo, tenemos un gran conjunto de pruebas unitarias para nuestra aplicación C ++. Sin embargo, no usamos un marco de prueba de unidad. Simplemente utilizan una macro C que básicamente envuelve una afirmación y un cout. Algo como:
VERIFY(cond) if (!(cond)) {std::cout << "unit test failed at " << __FILE__ << "," << __LINE__; asserst(false)}
Luego simplemente creamos funciones para cada una de nuestras pruebas como
void CheckBehaviorYWhenXHappens()
{
// a bunch of code to run the test
//
VERIFY(blah != blah2);
// more VERIFY's as needed
}
Nuestro servidor CI recoge "error de prueba de unidad" y falla la compilación, enviando el mensaje por correo electrónico a los desarrolladores.
Y si tenemos un código de configuración duplicado, simplemente lo refactorizamos como lo haríamos con cualquier otro código duplicado que tendríamos en producción. Lo ajustamos detrás de las funciones auxiliares, hacemos que algunas clases de prueba terminen configurando escenarios de uso frecuente.
Sé que hay marcos como CppUnit y prueba de unidad de impulso. Me pregunto qué valor agregan estos. ¿Me estoy perdiendo lo que estos traen a la mesa? ¿Hay algo útil que pueda obtener de ellos? Dudo en agregar una dependencia a menos que agregue un valor real, especialmente porque parece que lo que tenemos es muy simple y funciona bien.
fuente
Parece que ya usas un framework, uno hecho en casa.
¿Cuál es el valor agregado de los marcos más populares? Diría que el valor que agregan es que cuando tiene que intercambiar código con personas ajenas a su empresa, puede hacerlo, ya que se basa en el marco conocido y ampliamente utilizado .
Un marco hecho en casa, por otro lado, te obliga a nunca compartir tu código o a proporcionar el marco en sí, lo que puede volverse engorroso con el crecimiento del marco en sí.
Si le da su código a un colega tal como está, sin explicación y sin marco de prueba de unidad, no podrá compilarlo.
Un segundo inconveniente de los marcos caseros es la compatibilidad . Los marcos de prueba de unidad populares tienden a garantizar la compatibilidad con diferentes IDE, sistemas de control de versiones, etc. Por el momento, puede que no sea muy importante para usted, pero ¿qué sucederá si algún día necesita cambiar algo en su servidor de CI o migrar? a un nuevo IDE o un nuevo VCS? ¿Reinventarás la rueda?
Por último, pero no menos importante, los marcos más grandes proporcionan más características que puede necesitar implementar en su propio marco algún día.
Assert.AreEqual(expected, actual)
No siempre es suficiente. ¿Qué pasa si necesita:medir precisión?
prueba nula si se ejecuta durante demasiado tiempo? Reimplementar un tiempo de espera puede no ser sencillo incluso en lenguajes que facilitan la programación asincrónica.
probar un método que espera que se produzca una excepción?
tiene un código más elegante?
está bien, pero ¿no es más expresivo tu intención de escribir la siguiente línea?
fuente
Como otros ya han dicho, usted ya tiene su propio marco de trabajo hecho en casa.
La única razón que puedo ver para usar algún otro marco de prueba sería desde el punto de vista del "conocimiento común" de la industria. Los nuevos desarrolladores no tendrían que aprender su forma casera (aunque parece muy simple).
Además, otros marcos de prueba pueden tener más funciones que podría aprovechar.
fuente
Ya tiene un marco, incluso si es simple.
Según veo, las principales ventajas de un marco más grande es la capacidad de tener muchos tipos diferentes de afirmaciones (como el aumento de afirmaciones), un orden lógico para las pruebas unitarias y la capacidad de ejecutar solo un subconjunto de pruebas unitarias en un momento. Además, el patrón de las pruebas de xUnit es bastante agradable de seguir si puede, por ejemplo, el setUP () y el tearDown (). Por supuesto, eso te encierra en dicho marco. Tenga en cuenta que algunos marcos tienen una mejor integración simulada que otros, por ejemplo, simulacro de Google y prueba.
¿Cuánto tiempo le llevará refactorizar todas sus pruebas unitarias a un nuevo marco? Los días o unas pocas semanas tal vez valen la pena, pero más tal vez no tanto.
fuente
A mi modo de ver, ambos tienen la ventaja y están en una "desventaja" (sic).
La ventaja es que tiene un sistema con el que se siente cómodo y que funciona para usted. Está contento de que confirme la validez de su producto, y probablemente no encuentre ningún valor comercial al intentar cambiar todas sus pruebas para algo que use un marco diferente. Si puede refactorizar su código y sus pruebas recogen los cambios, o mejor aún, si puede modificar sus pruebas y su código existente no pasa las pruebas hasta que se refactorice, entonces tendrá todas sus bases cubiertas. Sin embargo...
Una de las ventajas de tener una API de prueba de unidad bien diseñada es que hay una gran cantidad de soporte nativo en la mayoría de los IDE modernos. Esto no afectará a los usuarios de VI y emacs de núcleo duro que se burlan de los usuarios de Visual Studio, pero para aquellos que usan un buen IDE, tienen la capacidad de depurar sus pruebas y ejecutarlas dentro El IDE mismo. Esto es bueno, sin embargo, hay una ventaja aún mayor dependiendo del marco que use, y eso está en el lenguaje utilizado para probar su código.
Cuando digo lenguaje , no estoy hablando de un lenguaje de programación, sino que estoy hablando de un conjunto de palabras enriquecidas envueltas en una sintaxis fluida que hace que el código de prueba se lea como una historia. En particular, me he convertido en un defensor del uso de los marcos BDD . Mi API favorita de DotNet BDD es StoryQ, pero hay varios otros con el mismo propósito básico, que es sacar un concepto de un documento de requisitos y escribirlo en código de forma similar a como está escrito en la especificación. Sin embargo, las API realmente buenas van aún más lejos, interceptando cada declaración individual dentro de una prueba e indicando si esa declaración se ejecutó con éxito o falló. Esto es increíblemente útil, ya que puede ver toda la prueba ejecutada sin regresar antes, lo que significa que sus esfuerzos de depuración se vuelven increíblemente eficientes, ya que solo necesita enfocar su atención en las partes de la prueba que fallaron, sin necesidad de decodificar toda la llamada secuencia. La otra cosa buena es que el resultado de la prueba muestra toda esta información,
Como ejemplo de lo que estoy hablando, compare lo siguiente:
Usando afirmaciones:
Usando una API BDD fluida: (Imagine que los bits en cursiva son básicamente punteros de método)
Ahora que la sintaxis BDD es más larga y más amplia, y estos ejemplos son terriblemente artificiales, sin embargo, para situaciones de prueba muy complejas en las que muchas cosas están cambiando en un sistema como resultado de un comportamiento determinado del sistema, la sintaxis BDD le ofrece una clara descripción sobre lo que está probando y cómo se ha definido su configuración de prueba, y puede mostrar este código a un no programador y ellos comprenderán instantáneamente lo que está sucediendo. Además, si "variable_A" falla la prueba en ambos casos, el ejemplo Asserts no se ejecutará más allá de la primera afirmación hasta que haya solucionado el problema, mientras que la API de BDD ejecutará todos los métodos llamados en la cadena, a su vez, e indicará qué partes individuales de la declaración estaban en error.
Personalmente, creo que este enfoque funciona mucho mejor que los marcos de xUnit más tradicionales en el sentido de que el lenguaje de prueba es el mismo lenguaje que sus clientes hablarán de sus requisitos lógicos. Aun así, me las arreglé para usar los marcos xUnit en un estilo similar sin necesidad de inventar una API de prueba completa para respaldar mis esfuerzos, y aunque las afirmaciones aún se cortocircuitarán, leerán más limpiamente. Por ejemplo:
Usando Nunit :
Si decide explorar utilizando una API de prueba unitaria, mi consejo es experimentar con un gran número de API diferentes durante un tiempo, y mantener una actitud abierta sobre su enfoque. Si bien defiendo personalmente BDD, sus propias necesidades comerciales pueden requerir algo diferente para las circunstancias de su equipo. Sin embargo, la clave es evitar adivinar su sistema existente. Siempre puede admitir sus pruebas existentes con algunas pruebas usando otra API si es necesario, pero ciertamente no recomendaría una gran reescritura de prueba solo para hacer que todo sea igual. A medida que el código heredado deja de usarse, puede reemplazarlo fácilmente y sus pruebas con un código nuevo, y pruebas usando una API alternativa, y esto sin necesidad de invertir en un esfuerzo importante que no necesariamente le dará ningún valor comercial real. En cuanto al uso de una API de prueba unitaria,
fuente
Lo que tienes es simple y hace el trabajo. Si te funciona, genial. No necesita un marco de prueba de unidad convencional, y dudaría en llevar a cabo el trabajo de portar una biblioteca existente de pruebas de unidad a un nuevo marco. Creo que el mayor valor de los marcos de pruebas unitarias es reducir la barrera de entrada; simplemente comienza a escribir pruebas, porque el marco ya está en su lugar. Ya pasó ese punto, por lo que no obtendrá ese beneficio.
El otro beneficio de usar un marco general, y es un beneficio menor, en mi opinión, es que los nuevos desarrolladores ya pueden estar al día en cualquier marco que esté utilizando, por lo que requerirán menos capacitación. En la práctica, con un enfoque directo como el que ha descrito, esto no debería ser un gran problema.
Además, la mayoría de los frameworks convencionales tienen ciertas características que su framework puede o no tener. Estas características reducen el código de plomería y hacen que sea más rápido y fácil escribir casos de prueba:
fuente