pruebas por guiado ejemplo driven development desarrollo atdd tdd

por - tdd wikipedia



¿Es el desarrollo basado en pruebas un enfoque normal en el desarrollo de juegos? (8)

Tengo curiosidad ya que todos los ejemplos de TDD que he visto están relacionados con la programación web. Y si no es un enfoque normal, ¿por qué no?


@Rune Una vez más, haga hincapié en la ''D'' en lugar de la ''T''. A nivel de unidad, las pruebas son una herramienta de pensamiento para ayudarlo a comprender lo que quiere y para impulsar el diseño del código. Ciertamente, en el nivel de la unidad, encuentro que acabo con un código más limpio y más robusto. Cuanto mejor sea la calidad de las piezas que coloco en el sistema, mejor encajarán con menos errores (pero no ninguno).

No es lo mismo en absoluto que el tipo de pruebas serias que necesitan los juegos.


Games from Within tiene un artículo que discute su uso de pruebas unitarias, las limitaciones de las pruebas unitarias con respecto a los juegos en particular, y un servidor de pruebas funcionales automatizado que configuraron para ayudar con esto.


La mayoría de los desarrolladores de juegos no están exactamente de acuerdo con las prácticas de desarrollo modernas. Agradecidamente.

Pero un modelo de desarrollo basado en pruebas enfatiza concentrarse en cómo se usaría algo primero y luego desarrollar lo que hace. En general, es bueno hacerlo, ya que lo obliga a concentrarse en cómo una característica en particular encaja en lo que sea que esté haciendo (por ejemplo, un juego).

Tan buenos desarrolladores de juegos hacen esto naturalmente. Simplemente no explícitamente.


La respuesta simple es "no", TDD no es un enfoque normal en el desarrollo de juegos. Algunas personas señalarán a Highmoon y Neil Llopis como ejemplos contrarios, pero es una gran industria y son las únicas personas que conozco que han abrazado por completo a TDD. Estoy seguro de que hay otros, pero son los únicos que conozco (y he estado en la industria durante 5 años).

Creo que muchos de nosotros hemos incursionado en pruebas de unidad en algún momento, pero por una razón u otra no se ha consolidado. Hablando desde la experiencia personal, es difícil para un estudio de juegos cambiar a TDD. Por lo general, se mantiene una base de código de proyecto a proyecto, y la aplicación de TDD a una base de código grande existente es tediosa y, en gran medida, ingrata. Estoy seguro de que con el tiempo resultaría fructífero, pero hacer que los programadores de juegos lo compren es difícil.

He tenido cierto éxito en escribir pruebas unitarias para código de motor de juego de bajo nivel, porque este código tiende a tener muy pocas dependencias y se puede encapsular fácilmente. Esto siempre ha estado probando después del hecho y no TDD. El código de juego de nivel superior suele ser más difícil para escribir pruebas porque tiene muchas más dependencias y, a menudo, está asociado con datos y estados complejos. Tomando la IA como ejemplo, para probar la IA se requiere algún tipo de contexto, es decir, una malla de navegación y otros objetos en el mundo. La configuración de ese tipo de prueba de forma aislada puede ser no trivial, especialmente si los sistemas involucrados no fueron diseñados para ello.

Lo que es más común en el desarrollo de juegos, y he tenido más éxito personal con las pruebas de humo. A menudo verá pruebas de humo utilizadas junto con la integración continua para proporcionar diversos tipos de comentarios sobre el comportamiento del código. Hacer pruebas de humo es más fácil porque puede hacerse simplemente introduciendo datos en el juego y leyendo información, sin tener que compartimentar su código en pequeñas piezas comprobables. Si tomas AI como el ejemplo nuevamente, puedes decirle al juego que cargue un nivel y proporcione un script que carga a un agente de AI y le da comandos. Luego, simplemente determine si el agente realiza esos comandos. Esta es una prueba de humo en lugar de una prueba de unidad porque está ejecutando el juego como un todo y no está probando el sistema de inteligencia artificial de forma aislada.

En mi opinión, es posible obtener una cobertura de prueba decente por unidad probando el código de bajo nivel mientras que el humo prueba los comportamientos de alto nivel. Creo (espero) que otros estudios también estén adoptando un enfoque similar.

Si mi opinión de TDD suena algo ambigua es porque lo es. Todavía estoy un poco en la valla al respecto. Si bien veo algunos beneficios (pruebas de regresión, énfasis en el diseño antes del código), aplicarlos y aplicarlos mientras se trabaja con un código base preexistente parece una receta para los dolores de cabeza.


Probablemente la razón principal es que TDD es preferido por aquellos con idiomas más propicios para ello. Pero, aparte de eso, los juegos en sí mismos son una mala combinación para el paradigma de todos modos.

En términos generales (y sí, quiero decir en términos generales, así que, por favor, no me sumerja en los contraejemplos), el diseño basado en pruebas funciona mejor para sistemas controlados por eventos y no tan bien para sistemas de simulación. Aún puede usar pruebas en sus componentes de bajo nivel en juegos, ya sea mediante pruebas o simplemente pruebas unitarias, pero para tareas de más alto nivel rara vez hay algún tipo de evento discreto que pueda simular con resultados deterministas.

Por ejemplo, una aplicación web normalmente tiene entradas muy distintas (una solicitud HTTP), cambia una cantidad muy pequeña de estado (por ejemplo, registros en la base de datos) y genera una salida en gran parte determinista (por ejemplo, página HTML). Se puede verificar fácilmente su validez, y dado que generar la entrada es simple, es trivial crear pruebas.

Sin embargo, con los juegos, la entrada puede ser difícil de simular (especialmente si es necesario que ocurra en un cierto punto ... piense en superar las pantallas de carga, las pantallas de menú, etc.), la cantidad de estado que cambia puede ser grande (por ejemplo, , si tiene un sistema físico o una IA reactiva compleja y la salida rara vez es determinista (el principal culpable es el uso de números aleatorios aquí, aunque la pérdida de precisión de punto flotante es otra, como las especificaciones de hardware o el tiempo de CPU disponible). o el rendimiento de un hilo de fondo, etc.).

Para realizar TDD, debe saber exactamente lo que espera ver en un determinado evento y tener una forma precisa de medirlo, y ambos son problemas difíciles con simulaciones que evitan eventos discretos, incluyen deliberadamente factores aleatorios, actúan de manera diferente en diferentes máquinas, y tienen salidas analógicas como gráficos y audio.

Además, hay un problema práctico masivo que es el tiempo de inicio del proceso. Muchas de las cosas que querrá probar requieren la carga de grandes cantidades de datos, y si se burla de los datos, realmente no está probando el algoritmo. Teniendo esto en cuenta, rápidamente no es práctico tener ningún tipo de andamiaje de prueba que solo realice tareas individuales. Puede ejecutar pruebas en un servidor web sin tener que desactivar el servidor web cada vez, lo que rara vez es posible con juegos a menos que realice las pruebas desde un lenguaje de scripting incorporado (lo cual es razonable y, de hecho, tiene lugar en la industria).

Por ejemplo, deseas agregar la representación de sombras volumétrica a tus edificios dentro del juego. Por lo tanto, debe escribir una prueba que inicie todos los subsistemas necesarios (por ejemplo, renderizador, juego, cargadores de recursos), carga en edificios (incl. Malla, materiales / texturas), carga en una cámara, coloque esa cámara en apunte al edificio, habilite las sombras, renderice una escena, y luego de alguna manera decida si las sombras realmente aparecen en el búfer de cuadros. Es menos que práctico. En realidad, ya tendrías todo este andamiaje en la forma de tu juego, y simplemente lo encenderías para realizar una prueba visual además de cualquier aseveración dentro del propio código.


Si se está refiriendo a la práctica de escribir y mantener pruebas unitarias para cada parte del código, me atrevería a adivinar y afirmar que esto no es un uso generalizado en la industria del juego. Hay muchas razones para esto, pero puedo pensar en 3 obvias:

  • Cultural. Los programadores son conservadores, los programadores de juegos lo son doblemente.
  • Práctico. TDD no se adapta muy bien al dominio del problema (demasiadas partes móviles).
  • Crunchológico. Nunca hay suficiente tiempo.

El paradigma TDD funciona mejor en dominios de aplicación que no son muy estadísticos, o al menos donde las partes móviles no se mueven todas al mismo tiempo, para ponerlo de manera coloquial.

TDD es aplicable a partes del proceso de desarrollo del juego (bibliotecas básicas y similares), pero "probar" en esta línea de trabajo generalmente significa ejecutar un vuelo automatizado, pruebas aleatorias de claves, sincronización de cargas, seguimiento de picos de fps, asegurarse de que el jugador pueda No te muevas para causar inestabilidades visuales, cosas así. El autómata también es muy a menudo un humanoide.

TDD puede ser una herramienta útil, pero su estado como una bala de plata que debe ser omnipresente cuando se crea un sistema es bastante cuestionable. El desarrollo no debe ser conducido por pruebas, sino por la razón. Sin embargo, el RDD es un acrónimo horrible, no se va a poner al corriente. ;)


TDD no es realmente un enfoque "normal" en ninguna parte, ya que aún es relativamente nuevo y todavía no se entiende ni se acepta universalmente. Eso no quiere decir que algunas tiendas no funcionen de esa manera ahora, pero todavía me sorprende escuchar a alguien que lo use en este momento.


TDD se ha convertido en un enfoque preferido por los desarrolladores de software que toman en serio su profesión. [ IEEE:TDD ] Los beneficios del enfoque son significativos, y los costos son bajos en comparación. [ Las tres leyes de TDD ]

No hay dominios de software para los cuales TDD sea inapropiado o inefectivo. Sin embargo, hay dominios en los que es desafiante. El juego pasa a ser uno de estos.

En realidad, el desafío no es tanto el juego como la IU. La razón por la que la IU es un desafío es que a menudo no sabes cómo quieres que se vea la IU hasta que la veas. La interfaz de usuario es una de esas cosas con las que tienes que jugar. Hacerlo bien es un proceso profundamente iterativo que está lleno de giros, vueltas, callejones sin salida y callejones sin salida. Escribir las pruebas primero para UI es probable que sea difícil y derrochador.

Ahora, antes de que todo el mundo ruge y diga: "El tío Bob dice: ''No hagas TDD para UI''", déjame decir esto. El hecho de que sea difícil hacer TDD puro para la interfaz de usuario no significa que no se pueda realizar TDD puro para casi todo lo demás. Gran parte de los juegos se trata de algoritmos, y puede usar TDD con esos algoritmos para deleite de su corazón. Es cierto, especialmente en los juegos, que algunos de esos algoritmos son el tipo de código con el que tienes que jugar, al igual que la interfaz de usuario, por lo que probablemente no sean susceptibles de ser probados primero . Pero hay muchos otros códigos algorítmicos que pueden y deben escribirse primero.

El truco aquí es seguir el principio de responsabilidad única (SRP) y separar los tipos de código con los que tiene que lidiar, de los tipos que son deterministas. No ponga algoritmos fáciles de probar en su interfaz de usuario. No mezcle su código especulativo con su código no especulativo. Mantenga las cosas que cambian por la razón A separada de las cosas que cambian por la razón B.

Además, tenga esto en cuenta: el hecho de que un código sea difícil de probar primero , no significa que este código sea difícil de probar en segundo lugar . Una vez que haya manipulado, modificado y conseguido que el código funcione de la forma que desee, puede escribir las pruebas que demuestren que el código funciona de la manera que usted piensa. (Te sorprenderás de cuántas veces encuentras errores al hacer esto).

El problema con las pruebas de escritura "después del hecho" es que a menudo el código está tan acoplado que es difícil escribir los tipos de pruebas quirúrgicas que son más útiles. Entonces, si está escribiendo el tipo de código que es difícil de probar primero , debe tener cuidado de seguir el principio de inversión de dependencia (DIP) y el principio de apertura / cierre (OCP) para mantener el código lo suficientemente desacoplado para probar después de el hecho.