Dernière mise à jour : décembre 2019. Durée de lecture : 6 min.

Testez votre code de jeu avec Unity Test Framework

Ce que vous trouverez sur cette page : des conseils sur l’utilisation de Unity Test Framework (UTF) pour l’assurance qualité de vos projets. UTF est l’un des outils d’assurance qualité les plus performants. Il permet exécuter des tests automatisés à la fois dans l’éditeur et sur des plateformes prises en charge. Et il est disponible pour tous les utilisateurs Unity !  

Une nouvelle API Test Runner apporte davantage de flexibilité et d’extensibilité à UTF, pour la plupart de vos besoins de test. UTF est disponible via le Package Manager Unity, ce qui nous permet de transmettre les correctifs et les mises à jour plus rapidement. Cela signifie aussi que vous pouvez accéder localement au code source de UTF, le consulter, le parcourir lors du débogage et le modifier.  

Pour en savoir plus, regardez la présentation de l'UTF à l'Unite Copenhagen, animée par Richard Fine et Christian Warnecke, développeurs de tests et d’outils Unity.

Testez le code de votre jeu avec Unity Test Framework

Premiers pas avec Unity Test Framework

Si vous êtes un nouvel utilisateur de Unity Test Framework (UTF), veuillez commencer par lire la documentation. En bref, UTF permet aux utilisateurs de Unity de tester leur code à la fois en mode Edit et en mode Play, ainsi que sur des plateformes cibles comme Standalone, Android, iOS, etc.

UTF utilise une intégration Unity de NUnit, une bibliothèque de tests unitaires open source pour les langages .Net. Pour plus d'informations sur NUnit, consultez le site Web officiel NUnit et la documentation NUnit sur GitHub

Ces articles de blog seront utiles aux nouveaux utilisateurs :

Performance benchmarking in Unity: How to get started

Testing test-driven development with the Unity Test Runner

Présentation de l’API Test Runner

Vous pouvez exécuter vos tests par programme à partir de tout script via l’API Test Runner (voir API ci-dessous). Elle vous permet de récupérer une liste de tests qui s’exécuteront en mode Edit, en mode Play, ou les deux, sans les exécuter. Vous pouvez vous connecter à certains rappels d’enregistrement/de désenregistrement au début et à la fin de chaque test, ainsi qu’à tout niveau du cycle de test, autrement dit sur l’ensemble de l'assemblage de tests, sur chaque montage de test particulier et sur tout(e) classe de test et test. 

Au début de chaque test, vous obtenez des informations sur l’itinéraire de test sur le point d’être exécuté. Une fois le test terminé, ses résultats s’affichent. 

En plus d'exécuter UTF en mode Play dans l’Éditeur Unity, un nouveau point de personnalisation vous permet de l’exécuter sur des appareils cibles. Ceci est invoqué avant la compilation du script Player. Par exemple, vous pouvez modifier les options de compilation du script Player pour changer les paramètres d’exécution de test et spécifier les emplacements de compilation.

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);

Scinder la compilation et l’exécution

Il est utile de scinder les processus de compilation et d’exécution si vous souhaitez exécuter des tests sur un appareil cible qui n’est pas connecté à votre machine locale (par exemple, si celui-ci ou plusieurs appareils se trouvent dans le cloud). 

Pour ce faire, vous devez tout d’abord personnaliser le processus de compilation du script Player test lui-même. Voici comment procéder : 

  • Désactivez l’exécution automatique (AutoRun), de sorte qu’après compilation du script Player, elle ne démarre pas et n’exécute pas les tests. 
  • Enregistrez le script Player dans un emplacement connu plutôt que dans le dossier temporaire du système (où il serait enregistré par défaut). 

Ajoutez ensuite des rapports de résultats personnalisés du côté du script Player (à l’aide de l’interface de rappel) pour recueillir tous les résultats et les enregistrer dans un fichier XML ou sous tout autre format adapté à votre projet. 

Consultez les exemples de code suivants pour scinder compilation et exécution. Dans la session Unite (à 6:28), Richard Fine vous guide pas à pas dans le code des deux parties de cette application (la compilation et la création de rapports de résultats).

Scinder la compilation et l’exécution : compilation

Compilation :

 

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;
   }
}

Scinder la compilation et l’exécution : enregistrer les résultats lors de l’exécution

Exécution : 

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);
   }
}

Lancement de tests spécifiques à partir d’un élément de menu

Souvent, lorsque les développeurs rédigent des validations, les résultats s’affichent dans la fenêtre Console, où il est facile de les perdre dans le flux de messages. Et si vous pouviez plutôt obtenir les résultats de validation dans une suite de tests avec des indicateurs clairs, dans un espace dédié dans l’Éditeur ? C'est possible en lançant des tests spécifiques pour un élément de menu.  

Vous commencez avec une méthode liée à un élément de menu, tout comme vous le feriez avec n’importe quel autre élément de menu d’extension de l’Éditeur. Cette méthode crée ensuite un objet de rappel ScriptableObject. Vous utilisez un objet programmable au lieu d’une classe régulière afin que les tests puissent exécuter des tâches comme un rechargement de domaine tout en conservant vos rappels en l’état. Lorsque l'objet programmable est activé, il est enregistré pour les rappels, et lorsqu’il est désactivé, il est désenregistré. 

Vous configurez ensuite des filtres. Il arrive souvent qu’au lancement d’un test pour un élément de menu, vous souhaitiez exécuter des tests pour une catégorie ou un groupe spécifique. Les filtres permettent d’exécuter le test de manière asynchrone. Il s’exécutera au fil de plusieurs images, permettant ainsi à UnityTest, UnitySetUp et UnityTearDown de cocher la boucle du moteur pendant le test. Lorsque le test est terminé et qu'il enregistre RunFinished, vous pouvez le configurer pour afficher un message ou ouvrir une fenêtre de résultats (ce qui correspond le mieux à votre flux de production).

Consultez l’exemple de code ci-dessous. Richard passe en revue la configuration du code pour cette application dans la session Unite (à 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);
   }

Exécution de tests avant la compilation

L’exécution de tests avant la compilation peut s’avérer délicate, car le processus de compilation nécessite l’exécution des tests à partir d’un rappel. Il n’y a donc aucune possibilité de lancer la boucle de mise à jour du moteur. Cependant, l'avantage est que vous pouvez vérifier que les fonctionnalités de base sont opérationnelles avant de consacrer du temps à la compilation (ce qui peut prendre plusieurs minutes pour certains projets). 

Vous pouvez implémenter cette application à l’aide de l’interface IPreprocessBuildWithReport, de la même façon que vous le feriez pour tout autre type de prétraitement de compilation. Pour obtenir les résultats, enregistrez un rappel comme d'habitude.

Puisque vous ne pouvez pas passer en mode Play au milieu d’une compilation, vous pouvez utiliser l’API Test Runner pour exécuter des tests spécifiques en mode Edit. Vous pouvez sélectionner ces tests en les filtrant par catégorie, comme une catégorie de test de validation précompilation. Il est possible d’exécuter ces tests de manière synchrone. 

À l’issue du test, vérifiez les résultats. En cas de problème, vous pourrez lever une exception BuildFailed, ce qui entraînera l’abandon du processus de compilation. 

Cette application peut être divisée en deux parties : le ResultCollector et le préprocesseur, détaillées par Richard lors de sa présentation (à 15:20). 

Regarder la démonstration en direct de l’API Test Runner effectuée par Christian et Richard. Visionnez toute la session pour obtenir davantage de conseils en matière d'assurance qualité ! 

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;
   }
}

Vous avez aimé ce contenu ?

Ce site utilise des cookies dans le but de vous offrir la meilleure expérience possible. Consultez notre politique de cookies pour en savoir plus.

Compris