Última actualización: diciembre de 2019. Tiempo de lectura: 6 minutos

Prueba el código de tu juego con Unity Test Framework

Lo que encontrarás en esta página: Consejos sobre cómo usar Unity Test Framework (UTF) para asegurar la calidad (QA) de tus proyectos. El UTF es una de las herramientas más importantes para garantizar la calidad. Se utiliza para ejecutar pruebas automáticas tanto en el Editor como en plataformas compatibles. ¡Y está disponible para todos los usuarios de Unity!  

Una nueva API de Test Runner aporta mayor flexibilidad y capacidad de ampliación al UTF, a fin de que puedas adaptarlo para las pruebas que necesites. Está disponible a través de Unity Package Manager. Eso nos permite publicar las correcciones de errores y las nuevas actualizaciones con mayor rapidez. También significa que puedes acceder al código fuente del UTF de forma local. Puedes mirar el código fuente, seguirlo paso a paso durante el proceso de depuración y modificarlo.  

Para conocer toda la historia, mira la sesión sobre UTF en Unite Copenhague, con los desarrolladores de herramientas y pruebas de Unity Richard Fine y Christian Warnecke.

Prueba el código de tu juego con Unity Test Framework

Primeros pasos con Unity Test Framework

Si es la primera vez que usas Unity Test Framework (UTF), lee esta documentación a modo de introducción. En pocas palabras, el UTF permite que los usuarios de Unity prueben su código tanto en modo de edición (edit mode) como en modo de juego (play mode), y también en plataformas compatibles tales como Standalone, Android e iOS, entre otras.

UTF utiliza una integración de la biblioteca NUnit en Unity, que es una biblioteca de pruebas unitarias de código abierto para lenguajes .Net. Para obtener más información sobre NUnit, consulta el sitio web oficial de NUnit y la documentación de NUnit en GitHub

Para los usuarios principiantes, estas publicaciones de blog son muy informativas:

Performance benchmarking in Unity: How to get started (Comparación de rendimiento Unity: cómo comenzar)

Testing test-driven development with the Unity Test Runner (Pruebas para el desarrollo orientado a las pruebas con Unity Test Runner)

Descripción general de la API de Test Runner

Puedes ejecutar tus pruebas de forma programática a través de cualquier script mediante la API de Test Runner (consulta la API más abajo). Te permite obtener una lista de las pruebas que se ejecutarán en el modo de edición, el modo de juego, o ambos, sin tener que ejecutarlas. Puedes colocar una función de rellamada (callback) de registro/cancelación de registro al comienzo y al final de cada prueba y en cada nivel dentro del ciclo de prueba, es decir, en todo el conjunto de prueba, en cada unidad de prueba, en cada clase y en cada prueba individual. 

Al inicio de cada prueba, obtienes información acerca de la ruta de prueba que se está por ejecutar. Cuando la prueba termina, ves los resultados. 

Además de ejecutar el UTF en el modo de juego en Unity Editor, un nuevo punto de personalización te permite ejecutarlo en los dispositivos de destino. La llamada se produce antes de que se compile el jugador. Puedes modificar las opciones de compilación del jugador, por ejemplo, para cambiar los ajustes con que se ejecuta la prueba y especificar las ubicaciones donde se encuentra el código de compilación.

TestRunnerAPI.cs (C#)
void Execute(ExecutionSettings executionSettings);
void RegisterCallbacks<T>(T testCallbacks, int priority = 0) where T : ICallbacks;
void UnregisterCallbacks<T>(T testCallbacks) where T : ICallbacks;
void RetrieveTestList(TestMode testMode, Action<ITestAdaptor> callback);

Separa la compilación de la ejecución

Separar los procesos de compilación y ejecución es útil cuando quieres realizar pruebas en un dispositivo de destino que no está conectado a tu máquina local, por ejemplo, si se encuentra en la nube (o si se trata de múltiples dispositivos en la nube). 

Para esto, primero tienes que personalizar el proceso de compilación del jugador mismo. Estos son los pasos para hacerlo: 

  • Desactiva la ejecución automática. Eso evitara que inicie y ejecute las pruebas cuando compiles el jugador. 
  • Guarda el archivo en una ubicación conocida en lugar de dejarlo en la carpeta temporal del sistema (que es el lugar donde se guarda de forma predeterminada). 

Luego, agrega tu informe de resultados personalizado correspondiente al jugador (empleando la interfaz de rellamada, o callback) para captar todos los resultados y guardarlos en un archivo XML o en el formato que funcione mejor para tu proyecto. 

Consulta los siguientes ejemplos de código para ver cómo separar la compilación de la ejecución. En la sesión de Unite (en el minuto 6:28), Richard Fine te guía paso a paso por el código en ambas partes de esta aplicación: la compilación y el informe de resultados.

Separa la compilación de la ejecución: compilación

Compilación:

 

SplitBuildAndRun:build.cs (C#)
[assembly:TestPlayerBuildModifier(typeof(SetupPlaymodeTestPlayer))]
public class SetupPlaymodeTestPlayer : ITestPlayerBuildModifier {
   public BuildPlayerOptions ModifyOptions(BuildPlayerOptions playerOptions) {
   	playerOptions.options &= ~(BuildOptions.AutoRunPlayer | BuildOptions.ConnectToHost);
   	var buildLocation = Path.GetFullPath("TestPlayers");
   	var fileName = Path.GetFileName(playerOptions.locationPathName);
   	if (!string.IsNullOrEmpty(fileName))
       	buildLocation = Path.Combine(buildLocation, fileName);
   	playerOptions.locationPathName = buildLocation;
   	return playerOptions;
   }
}

Separa la compilación de la ejecución: guarda los resultados en la ejecución

Ejecución: 

SplitBuildAndRun:SaveResults.cs (C#)
[assembly:TestRunCallback(typeof(ResultSerializer))]
public class ResultSerializer : ITestRunCallback {
   public void RunStarted(ITest testsToRun) { }
   public void TestStarted(ITest test) { }
   public void TestFinished(ITestResult result) { }
   public void RunFinished(ITestResult testResults) {     
   	var path = Path.Combine(Application.persistentDataPath, "testresults.xml");
   	using (var xw = XmlWriter.Create(path, new XmlWriterSettings{Indent = true}))
       	testResults.ToXml(true).WriteTo(xw);
   	System.Console.WriteLine($"***\n\nTEST RESULTS WRITTEN TO\n\n\t{path}\n\n***");
   	Application.Quit(testResults.FailCount > 0 ? 1 : 0);
   }
}

Cómo iniciar pruebas específicas desde un elemento del menú

Con frecuencia, cuando los desarrolladores escriben validaciones, los resultados se muestran en la ventana de la consola, donde es muy probable que se pierdan entre el flujo de mensajes. ¿Qué sucedería si, en cambio, pudieras obtener los resultados de validación en un conjunto de prueba con indicadores claros en un lugar dedicado del Editor? Puedes hacerlo iniciando pruebas específicas para un elemento del menú.  

Comienzas con un método que está conectado a un MenuItem (elemento del menú), exactamente de la misma forma que lo harías con cualquier otro elemento del menú de extensiones del Editor. Luego, ese método crea un objeto de rellamada (callback) de ScriptableObject. Utilizas un ScriptableObject en lugar de una clase común para que las pruebas puedan hacer cosas tales como que vuelva a cargarse un dominio mientras que las rellamadas se mantienen intactas. Si el ScriptableObject está activado, está registrado para las rellamadas. Si está desactivado, no está registrado. 

Luego, configuras los filtros. Con frecuencia, cuando lanzas una prueba para un MenuItem, seguramente quieras ejecutar pruebas para una categoría o grupo específico. Puedes utilizar filtros para ejecutar la prueba de forma asincrónica. Se ejecutará al cabo de varios frames, lo que permitirá que UnityTest, UnitySetUp y UnityTearDown pasen por el bucle del motor durante la prueba. Cuando la prueba haya terminado y registre RunFinished (ejecución finalizada), puedes hacer que muestre un mensaje o que abra la ventana de resultados, lo que tenga más sentido para tu flujo de trabajo.

Consulta el ejemplo de código a continuación. Richard explica la configuración del código para esta aplicación en la sesión de Unite (en el minuto 11:50).  

LaunchTestsFromMenuItem.cs (C#)
public class RunTestsFromMenu : ScriptableObject, ICallbacks {
   [MenuItem(“Tools/Run useful tests”)] public static void DoRunTests() {
   	CreateInstance<RunTestsFromMenu>().StartTestRun();
   }
   private void StartTestRun() {
   	hideFlags = HideFlags.HideAndDontSave;
   	CreateInstance<TestRunnerApi>().Execute(new ExecutionSettings {
       	filters = new [] { new Filter{ categoryNames = new[] { “UsefulTests” }}}
   	});
   }
   public void OnEnable() { CreateInstance<TestRunnerApi>().RegisterCallbacks(this); }
   public void OnDisable() { CreateInstance<TestRunnerApi>().UnregisterCallbacks(this); }
   /* ...RunStarted, TestStarted, TestFinished... */
   public void RunFinished(ITestResultAdaptor result) {       
   	…
   	DestroyImmediate(this);
   }

Cómo ejecutar las pruebas antes de compilar

Ejecutar las pruebas antes de compilar puede ser complicado porque el proceso de compilación requiere que las pruebas se realicen desde una rellamada (callback), por lo que no hay oportunidad de activar el bucle de actualización del motor. Pero la ventaja es que puedes asegurarte de que la funcionalidad básica esté funcionando antes de dedicar tiempo a la compilación en sí (que, en algunos proyectos, puede tomar varios minutos). 

Puedes implementar esta aplicación utilizando la interfaz IPreprocessBuildWithReport, de la misma forma en que implementarías cualquier otro tipo de preprocesamiento de la compilación. Para obtener los resultados, registra una rellamada de la forma habitual.

Dado que no puedes ingresar al modo de juego en medio de la compilación, puedes usar la API de Test Runner para ejecutar pruebas específicas en el modo de edición. Puedes seleccionar estas pruebas filtrando por categorías; por ejemplo, la categoría de pruebas de validación antes de la compilación. Puedes ejecutar estas pruebas de forma asincrónica. 

Una vez finalizada la prueba, consulta los resultados. Puedes poner una excepción de BuildFailed (error de compilación) que se active en caso de error. Así, se cancelará el proceso de compilación. 

Esta aplicación puede dividirse en dos partes: el ResultCollector (recopilador de resultados) y el preprocesador. Richard habla sobre esto en su charla (en el minuto 15:20). 

Mira cómo Christian y Richard demuestran en vivo el uso de la API de Test Runner. Mira toda la sesión para ver aún más consejos de QA. 

RunTestsBeforeBuild.cs (C#)
   public ITestResultAdaptor Result { get; private set; }     
   public void RunStarted(ITestAdaptor testsToRun) { }
   public void TestStarted(ITestAdaptor test) { }
   public void TestFinished(ITestResultAdaptor result) { }
   public void RunFinished(ITestResultAdaptor result)
   {
   	Result = result;
   }
}

¿Te gustó este contenido?

Usamos cookies para brindarte la mejor experiencia en nuestro sitio web. Visita nuestra página de política de cookies si deseas más información.

Listo