Pour changer de rythme, j'aimerais faire un petit journal de développement. Il y a quelque temps, j'ai participé à un game jam et j'ai créé ce jeu – – un petit jeu de réflexion dans lequel vous placez du fromage dans le labyrinthe pour attirer les souris. C'était amusant, mais il y avait évidemment quelques défauts. Of Mice and Bad Choices L’un des principaux problèmes est que le comportement des souris n’est pas intuitif. Les joueurs ont mentionné qu'ils s'attendraient à ce que les souris soient repoussées par un fromage qu'elles n'aiment pas, et pas seulement par le gel. De plus, la mise en œuvre de cette mécanique permettrait une conception de puzzle beaucoup plus riche. Je pense donc que c'est une bonne opportunité pour savoir comment effectuer des tests automatisés dans Godot. Outils de test Il existe quelques frameworks de test disponibles pour Godot 4, mais celui qui m'a attiré est . GUT est assez simple : Godot Unit Test (GUT) Il peut être installé depuis AssetLib en un clic. Il fournit une classe que nous pouvons étendre pour nos scripts de test : ajoutez simplement des fonctions commençant par et écrivez quelques assertions – structure typique de test unitaire. test_ Il possède une interface utilisateur agréable avec la possibilité d'utiliser le débogueur de Godot et d'exécuter des tests individuels. Il peut être exécuté à partir de CLI et en CI (mais j'en parlerai plus tard). Mon cadre de test Pour ce cas particulier, je voulais avoir un moyen de définir des scénarios complexes, de la même manière que je définis les niveaux du jeu – dans l'éditeur du moteur plutôt que dans le code (de cette façon, les tests seraient plus proches de la réalité). Par conséquent, je veux faire ces choses: Avoir une fonction d'exécution unique qui prend une carte et exécute les tests. Avoir une collection de cartes, chacune ayant un ensemble de scénarios (cas de test) à exécuter. Ayez un moyen de définir des cas de test par glisser-déposer : placez une souris et définissez où elle doit être en N tours. Alors, déballons ça. Définitions des cas de test Définissons une nouvelle classe `MouseTestCase.` Nous voulons qu'elle hérite (car nous voulons le placer sur une scène. Et nous voulons qu'elle trouve l'un de ses enfants (que nous placerons nous-mêmes sur une scène) : une souris et sa position finale attendue (en tant que marqueur) Node2D extends Node2D class_name MouseTestCase @export var steps_left = 0 # How many steps to simulate @export var done = false @onready var mouse: Mouse = $Mouse @onready var expected_position = SnapUtils.get_tile_map_position($TestMarker.position) Maintenant, nous pouvons le mettre en scène, et c’est bon ! Nous savons où commence une souris, où elle doit aboutir et en combien d'étapes. Cartes de test Maintenant, créons-en davantage et créons une carte pour tester notre comportement répulsif. Ce comportement est quelque peu complexe, c'est pourquoi nous souhaitons couvrir de nombreux cas légèrement différents : Une souris veut s'éloigner du fromage qu'elle n'aime pas/ Une souris veut garder la direction du mouvement (c'est-à-dire éviter les virages) Une souris préfère les virages à gauche aux virages à droite et aux demi-tours La carte résultante définissant 12 cas de test pour couvrir ce comportement est présentée ci-dessus (imaginez à quel point il pourrait être fastidieux de coder en dur toutes ces coordonnées dans le code). Testeur La seule chose qui reste à faire est la fonction Test Runner. La fonction doit : Chargez la carte que nous avons définie ci-dessus. Simulez les étapes du jeu jusqu'à ce que tous les cas de test soient terminés. À chaque étape, parcourez tous les cas de test et, s’ils sont terminés, vérifiez si la position attendue est atteinte. Le code est assez simple. func run_level_with_mouse_test_cases(map_path: String): var level = load(map_path) map.load_level(level) var cases = MouseTestCase.cast_all_cases(get_tree().get_nodes_in_group(MouseTestCase.MTC_GROUP_NAME)) while (cases.any(func(case): return not case.done)): map.move_mice() for case in cases: if not case.done: case.steps_left -= 1 if case.steps_left == 0: case.done = true assert_eq(case.get_mouse_position(), case.expected_position, case.get_parent().name+"/"+case.name) J'imagine que cela va évoluer, mais la mise en œuvre actuelle est suffisante pour le moment. J'ai écrit les tests, implémenté la mécanique, et les tests confirment en fait que la mécanique est correctement implémentée ! Discussions Ici, j'ai montré une façon d'aborder les tests dans les jeux. Évidemment, il y a beaucoup plus de choses à améliorer ici, et j'encourage les lecteurs à prendre le code et le framework et à les adapter à leurs besoins. Comme toujours, le code est disponible sur GitHub : Vous pouvez également consulter qui introduit les tests. Pour les points bonus, si quelqu'un peut le faire travailler chez CI, ce serait génial. Acclamations. https://github.com/d-lowl/of-mice-and-bad-choices le PR spécifique