¿Cómo se hacen pruebas unitarias en un motor de juego?

23

Para mi vergüenza, nunca he escrito una prueba de unidad adecuada, solo pequeños programas de prueba no organizados que luego eliminaría después de que la prueba tuviera éxito. Realmente no tengo una idea clara de cómo se deben realizar las pruebas unitarias en un proyecto de juego. (Mi lenguaje es C ++.)

¿Debo tener un proyecto separado para cada subsistema en mi motor y una prueba asociada con él, y luego tener un proyecto / solución más grande que construya el motor real? Digamos, por ejemplo, que tengo el eventmódulo en mi motor; ¿Cómo debo manejar eso?

Paul Manta
fuente
pregunta interesante, cuando desarrollas tu motor, es bastante fácil probar la funcionalidad, pero ¿qué pasa con un gran proyecto en la prueba del juego?
Yevhen
2
No es una pena: las pruebas unitarias no son automáticamente una buena cosa.
o0 '.
1
Si nunca ha intentado usar pruebas unitarias, definitivamente es una pena.
Kristopher Johnson

Respuestas:

18

Primero, necesitaría un marco de prueba de unidad. En el pasado he usado UnitTest ++ y Google Test . El primero es muy liviano y el segundo es más destacado pero algo más engorroso. Se integra bien con Google Mock si alguna vez necesita ese tipo de cosas. Por supuesto, hay muchas otras opciones: consulte esta lista (por el autor final de UnitTest ++) y Wikipedia, por ejemplo.

Las pruebas unitarias consisten en escribir pruebas enfocadas para enfatizar determinados bits de código independientes aislados ("unidades") en varios escenarios. Si bien en algunos casos puede realizar pruebas unitarias de todo, por lo general no es práctico lograr una cobertura del 100% y, especialmente en los juegos, puede ser bastante difícil: es discutible si las pruebas unitarias de la salida de su procesador son significativas, útiles o una prueba de unidad "verdadera" independientemente.

Es importante recordar que cualquier prueba (automatizada) es mejor que ninguna prueba (automatizada). Por lo tanto, no debe estresarse demasiado por el hecho de que sus pruebas no son "pruebas unitarias verdaderas" y sentirse orgulloso de que simplemente tiene pruebas. Los marcos de pruebas unitarias suelen ser útiles para construir pruebas más flexibles y "no unitarias", ya que incluyen la funcionalidad para las pruebas de empaquetado y la notificación uniforme de fallas.

Te animo a que resucites tus pruebas anteriores y las conviertas en un proyecto de prueba usando uno de los marcos disponibles, algo que puedes ejecutar fácilmente de vez en cuando (o automáticamente como parte de una versión o compilación de integración) que ejecuta todos tus pruebas Escriba nuevas pruebas para los bits de código, ya que se hace evidente que podrían serle útiles, por ejemplo, si descubre un error sutil que podría haber detectado con una prueba, puede agregar uno para detectar cualquier regresión que pueda hacer en el futuro.

Probablemente descubrirá que es principalmente su código de utilidad de nivel inferior el que es susceptible de pruebas unitarias, en los juegos. Está bien, es un código de base que podría perturbar muchas capas superiores si se rompe.

No irá al purgatorio del programador por no tener pruebas para cada pequeña función y puerta lógica en su base de código, así que no pase más tiempo del necesario para escribir pruebas. Si tiene que pensar más o dedicar mucho más tiempo a escribir las pruebas para un módulo de lo que le llevó crear el módulo en primer lugar, puede estar perdiendo el tiempo. Las pruebas unitarias, las pruebas en general, son una herramienta que aprende a usar adecuadamente para ayudarlo, no una tarea que debe realizar para todo.

Josh
fuente
3
If you have to [...] spend significantly more time writing the tests [...] than it took you to author the module... Entonces tu módulo es demasiado complejo. Simplifícalo ahora, ¡te lo agradecerás en el futuro!
Jess Telford
3
@Jess Un módulo que es desproporcionadamente difícil de probar no necesariamente necesita ser simplificado. Hay muchas áreas donde las pruebas unitarias simplemente no son un buen uso del tiempo. Esto incluye gráficos, donde la salida puede variar mucho y aún ser aceptable; código que es poco probable que cambie en el futuro; o código donde el tipo de diseño abstracto y desacoplado que se necesitaría para facilitar las pruebas unitarias es mucho más feo, más propenso a errores, menos eficaz o menos intuitivo.
Casey Rodarmor
@rodarmor - de acuerdo. Hay una escala móvil de lo que es apropiado y lo que no. Al igual que con todo este tipo de respuestas, una talla no sirve para todos :)
Jess Telford
Para UnitTest ++, vaya a github.com/unittest-cpp/unittest-cpp . Todo lo demás está desactualizado.
Markus
4

Una "unidad" es el fragmento de código más pequeño que se puede probar, generalmente una sola función o clase. Una prueba unitaria es otra pieza de código que ejercita esa unidad de código para garantizar que se comporte como se pretende. Una sola unidad de código puede tener muchas pruebas para cubrir todos los casos.

Por lo general, las pruebas no se incluyen en la compilación principal de un proyecto. Más bien, hay una configuración de compilación separada para las pruebas que incluye todo el código de prueba y produce un programa que ejecuta todas las pruebas e informa los resultados. Un marco de prueba proporcionará todo el andamiaje para esto y se recomienda, aunque no es estrictamente necesario. Si es totalmente nuevo en las pruebas, es mejor que primero escriba su propio equipo de prueba ad-hoc, para asegurarse de comprender todo lo que está sucediendo.

Cubre la mayor cantidad de código que puedas con las pruebas, priorizando el código en el que no estás seguro, o el código que es frágil y que puede romperse por cambios futuros. Debe ejecutar las pruebas con frecuencia, idealmente después de cada cambio de código.

jedediah
fuente