2010-03-10 15 views
47

Me gusta la idea de realizar pruebas unitarias pero tengo problemas para aplicarla a la programación de juegos. Los juegos son muy explícitos y, a menudo, el código no se divide en unidades distintas. En mi experiencia, la mayoría de las funciones mutan el estado en lugar de devolver los valores.¿Las pruebas unitarias son viables en la programación de juegos?

Considere una acción simple como playerJump(height). Me encantaría tener un banco de pruebas que verifique una gran variedad de casos para asegurarse de que saltar salga siempre como se espera. Sin embargo, esta función probablemente no devuelva ningún valor y tenga el efecto secundario de player.velocity.y = -height y checkCollisions(player). No puedo pensar en una prueba de unidad clara para construir alrededor de esto.

¿Las pruebas unitarias simplemente no son viables en aplicaciones de gran estado como los juegos? ¿Las ventajas de las pruebas unitarias son tan grandes que valdría la pena programar juegos funcionalmente?


Actualización:

Juegos de Dentro tiene una serie de artículos en profundidad sobre el uso de Test Driven Development en los juegos. Los recomiendo a cualquier persona interesada en este tema. Aquí es el primer artículo:

http://gamesfromwithin.com/stepping-through-the-looking-glass-test-driven-game-development-part-1

+0

Para UnitTest ++, vaya a github.com/unittest-cpp/unittest-cpp. Todo lo demás está desactualizado. – Markus

Respuesta

29

A menudo, el código no se rompe en sí en unidades distintas.

Eso es solo diseño pobre. El código no se divide en nada. Usted, el diseñador, tiene que imponer una estructura en el código para que pueda demostrar que realmente funciona.

Sin embargo, esta función es probable que devolver ningún valor ...

Así?

... y tienen el efecto secundario de, player.velocity.y = -height y checkCollisions(player).

Luego, prueba para eso.

No puedo pensar en una prueba de unidad clara para construir alrededor de esto.

¿Por qué no? Acabas de dar una excelente especificación para los resultados de la función.

Es posible que necesite algunos objetos falsos para reemplazar el reproductor completo con un MockPlayer simplificado que es más fácil de probar.

Pero su especificación de comportamiento fue perfecta. Solo prueba las cosas que describes.

+4

Ah, ya veo. Creo que estoy interpretando "pruebas unitarias" demasiado literalmente. Me imagino probando las entradas y salidas de cada función. Más bien, la prueba podría validar restricciones en todo el sistema después de que se llame a una función. Gracias, siempre es bueno escapar de mi visión de embudo de programación :) – Kai

+0

@Kai: Como el cambio de estado del sistema es el * efecto secundario * de la función, todavía estás haciendo pruebas unitarias porque la función se prueba de forma aislada. Es muy fácil de probar con objetos falsos. No estoy seguro de por qué afirmarías que las pruebas unitarias están de alguna manera limitadas a las entradas y salidas de funciones adecuadas. –

+3

Un problema que tengo con esta idea es que la prueba podría terminar siendo tan complicada y propensa a errores como la unidad que se está probando. Tomemos, por ejemplo, los cambios de estado basados ​​en ticks, como la velocidad en la que no se cambian los valores configurables, pero los valores obtenibles cambian con cada tic. Uno tendría que crear una emulación del comportamiento de la velocidad para comprobar, efectivamente reimplementando el código de velocidad original, pero si no puede probar, ¿es la unidad la que falla o la prueba? – user515655

13

Las pruebas unitarias pueden ser útiles para muchas de las bibliotecas de bajo nivel que puedes usar con el código de juego, pero dudo seriamente que sea de mucha utilidad para las cosas de nivel superior. Los juegos suelen ser simulaciones y se basan en cantidades masivas de estado compartido que no se pueden burlar ni probar de forma significativa de forma aislada. A menudo, las funciones en los juegos no devuelven ningún tipo de valor que pueda verificar al instante, sino que establece un proceso en movimiento que debe completarse en algún momento en el futuro. Probar tal comportamiento vale la pena, pero requiere un enfoque significativamente diferente a la idea de la prueba de unidad de probar piezas de código de forma aislada.

+1

Esta es una descripción más clara del problema que estaba describiendo, gracias. Vale la pena ver si el proceso que se puso en marcha realmente terminó como se esperaba, pero parece requerir más tiempo que probar entradas y salidas de funciones simples. – Kai

0

Las pruebas unitarias simplemente no se preocupan en absoluto de lo "estado" de su unidad. Tiene una pieza de código más o menos autónoma, y ​​si su vector de entrada y salida es enorme, la prueba es difícil. Si estos vectores se establecen o no como estados antes y después de la ejecución no cambia un poco sobre la prueba. Sin embargo, si quiere decirnos que no puede pensar en una forma adecuada de definir casos de prueba como en la mayoría de los tutoriales/documentos de pruebas unitarias, es decir, el sujeto de prueba es algo así como "f (x) = y", entonces sí, estoy de acuerdo, será difícil probar que los pocos (x [100], y [99]) vectores con los que se obtiene una caña humana arrojan suficiente cobertura (¡numéricos!). Intente formular propiedades integradoras e invariantes e ir a pruebas automatizadas.

0

Eche un vistazo a PEX para la generación automática de pruebas unitarias. Generará pruebas unitarias para todas las posibles variaciones de entrada, lo que te ayudará a probar muchas combinaciones posibles.

+1

¿No es solo PEX .NET? Esta pregunta no está etiquetada como una pregunta de .NET. – Paddyslacker

16

La programación es la programación. Las pruebas unitarias son útiles para cualquier tipo de aplicación porque le ayudan a detectar y corregir errores (y, a menudo, lo más importante, las regresiones introducidas inadvertidamente al refactorizar el código) de forma inmediata y eficiente. Por supuesto hay áreas de alto nivel que son difíciles de probar unitarias, pero eso no es realmente para lo que son las pruebas unitarias: son principalmente para verificar que los métodos individuales o partes pequeñas de la base de código hagan lo que se supone deben hacer. hacer.

Para los comportamientos de nivel superior, debe aplicar otros enfoques de prueba (pruebas de regresión, por ejemplo: alimentar una secuencia fija de entradas en el juego y luego verificar que obtenga los mismos resultados cada vez, o generar vistas de cámara en ubicaciones fijas en todo un nivel y comprobando que siempre generan la misma imagen (o al menos razonablemente similar))

Su ejemplo de PlayerJump es uno de estos casos. Puede probar la unidad o la regresión aislándola con entradas constantes (coloque programáticamente el personaje del jugador en una ubicación fija en una escena de prueba simple y ejecute el evento de salto, luego verifique que las colisiones o el lugar de descanso final sean consistentes. biblioteca de diferentes objetos que el jugador puede saltar "en", puede cubrir una gran cantidad de casos de prueba (por ejemplo, que el salto tenga éxito sobre un espacio de la distancia de salto máxima prescrita).

Más allá de eso, los juegos requieren una gran cantidad de pruebas de juego (donde los usuarios reales simplemente lo juegan). Esto encontrará casos extraños que no cubriste con pruebas automáticas, pero lo más importante es que responderá a una pregunta que las pruebas automáticas nunca responderán: ¿se siente bien? "¿Es" divertido "? Estas son pruebas que solo un ser humano puede realizar.

+3

+1 Ten en cuenta que las pruebas unitarias de un procesador son casi imposibles. Algunas personas usan el método pixar e instantáneas de la misma escena de control desde el mismo ángulo con la misma iluminación y sombreadores y hacen una comparación de imágenes. – zebrabox

6

Mi experiencia con la unidad y las pruebas automáticas durante el desarrollo de Crysis 2 está disponible aquí: http://yetanothergameprogrammingblog.blogspot.com/2010/06/aaa-automated-testing.html Espero que ayude.

Resumen:

Las pruebas automatizadas mejor estabilidad entregables, el aumento de la productividad tanto para los creadores de contenidos e ingenieros Las pruebas automatizadas es una herramienta eficaz para mejorar la calidad del código y reducir las posibilidades de tener que trabajar horas extras la industria del juego como un todo es muy reaccionario en general, las pruebas automatizadas resuelven varios argumentos irracionales contra No lo llame pruebas, llámelo de otra manera, casi cualquier otra cosa (mire el desarrollo impulsado por el comportamiento) Sea flexible, escribir buenas pruebas es difícil y requiere habilidades que no están ampliamente disponibles en la industria del juego

+0

Hola, bienvenidos a Stack Overflow. Siempre es bienvenido un enlace a una solución potencial, pero agregue contexto alrededor del enlace para que los demás usuarios tengan una idea de qué es y por qué está allí. Siempre cite la parte más relevante de un enlace importante. Imagine que la página se mueve a otro servidor o el enlace directo cambia; los futuros usuarios no podrán beneficiarse de la respuesta. Por favor, eche un vistazo a [cómo responder] (http://stackoverflow.com/questions/how-to-answer). – Jesse

0

Muchos programadores de juegos usan el Entity-component-system architecture.Lo hacen porque hace que sea más fácil modificar el comportamiento de los objetos del juego. Pero, como sucede, también hace que resulte más fácil probar tu código en una unidad.

Cuestiones relacionadas