Exécutez des tests unitaires localement dans STM32CubeIDE sous Windows

Présentation


Tout le monde connaĂźt les avantages des tests unitaires. Tout d'abord, l'Ă©criture de tests en mĂȘme temps que le code vous permet de dĂ©tecter les erreurs plus tĂŽt et de ne pas perdre de temps par la suite sur un dĂ©bogage complexe et long. Dans le cas du dĂ©veloppement embarquĂ©, les tests unitaires ont des fonctionnalitĂ©s liĂ©es, d'une part, au fait que le code se trouve quelque part profondĂ©ment dans les entrailles de l'appareil et qu'il est assez difficile d'interagir avec lui, et d'autre part, le code est fortement liĂ© au matĂ©riel cible .


S'il y a des fragments dans le projet qui ne dĂ©pendent pas du matĂ©riel et implĂ©mentent en mĂȘme temps une logique assez complexe, pour eux, l'utilisation de tests unitaires sera la plus avantageuse. Par exemple, il peut s'agir de la mise en Ɠuvre d'un protocole de transfert de donnĂ©es, de divers calculs ou d'une machine Ă  Ă©tats de contrĂŽle.


Il existe trois façons d'exécuter des tests unitaires pour les plates-formes intégrées:


  1. Lancer directement sur la plateforme cible. Dans ce cas, vous pouvez travailler avec l'Ă©quipement de l'appareil et le code fonctionnera exactement de la mĂȘme maniĂšre que dans les conditions de combat. Cependant, pour les tests, vous aurez besoin d'un accĂšs physique Ă  l'appareil. De plus, le cycle de test sera assez long en raison de la nĂ©cessitĂ© de tĂ©lĂ©charger constamment du code sur l'appareil.
  2. Fonctionnant sur un Ă©mulateur. Cette mĂ©thode est bonne principalement parce qu'elle vous permet de travailler mĂȘme lorsque la plate-forme cible n'est pas disponible (par exemple, car elle n'a pas encore Ă©tĂ© effectuĂ©e). Les inconvĂ©nients sont la prĂ©cision limitĂ©e dans la reproduction du comportement du fer (et du monde environnant), ainsi que la difficultĂ© de crĂ©er un tel Ă©mulateur.
  3. En cours d'exĂ©cution sur la machine hĂŽte (localement). Cela ne fonctionnera pas avec l'Ă©quipement (vous pouvez utiliser des talons de test Ă  la place), mais les tests dĂ©marreront rapidement et fonctionneront, et vous n'avez pas besoin d'accĂ©der au pĂ©riphĂ©rique cible. Un bon exemple d'utilisation de cette mĂ©thode consiste Ă  tester la mise en Ɠuvre sur un microcontrĂŽleur d'un algorithme de calcul, qui en soi ne dĂ©pend pas du matĂ©riel, mais utilise les donnĂ©es du capteur de l'appareil. Tester un algorithme avec une vraie source de donnĂ©es sera trĂšs gĂȘnant, il est prĂ©fĂ©rable d'enregistrer une fois ces mesures et d'exĂ©cuter des tests dĂ©jĂ  sur les donnĂ©es stockĂ©es. Ce script exĂ©cutera des tests localement et sera discutĂ© plus tard.

Cette publication fournit un moyen de configurer les tests unitaires dans l'environnement STM32CubeIDE, basĂ©s sur Eclipse et destinĂ©s au dĂ©veloppement des contrĂŽleurs de la famille STM32. Le langage de dĂ©veloppement est C, mais les tests eux-mĂȘmes sont Ă©crits en C ++. Les tests s'exĂ©cuteront sur une machine hĂŽte Windows utilisant Cygwin. En tant que cadre de test, Google Test est utilisĂ©. Les rĂ©sultats seront affichĂ©s dans une fenĂȘtre de plug-in spĂ©ciale pour les tests unitaires, et ils peuvent ĂȘtre lancĂ©s avec un bouton du projet pour STM32:



La méthode décrite convient à d'autres environnements de développement basés sur Eclipse, à moins bien sûr que les bons fabricants les aient trop coupés pour le confort des développeurs. Cette méthode fonctionnera également avec CubeIDE sous Linux, sans avoir à se soucier de Cygwin.


Vous aurez besoin


  1. Cygwin 3.0.7 x86 (puisque les tests concernent un microcontrĂŽleur 32 bits, nous utiliserons Ă©galement un environnement 32 bits sur une plate-forme 64 bits)
  2. STM32CubeIDE 1.0.2 pour Windows.
  3. Google Test Framework 1.8.1

Installer Cygwin et STM32CubeIDE


Cygwin


Installez Cygwin, version x86. Dans le programme d'installation, sélectionnez des packages supplémentaires: gcc-core, g ++, binutils, automake, autoconf, cmake, libtool, gdb, make. Vous pouvez installer les derniÚres versions stables des packages.



Vous devez Ă©galement enregistrer les variables d'environnement:


CHEMIN: ...; C: \ <path_to_Cygwin> \ Cygwin \ bin; C: \ <path_to_Cygwin> \ Cygwin \ lib
chemin de classe : C: \ <path_to_Cygwin> \ Cygwin \ lib


STM32CubeIDE


L'environnement est installé comme d'habitude. Il est conseillé d'installer CubeIDE aprÚs Cygwin, car dans ce cas, Cube récupérera la chaßne d'outils Cygwin existante.


Tout d'abord, créez un projet C ++ pour la plate-forme Cygwin x86. Nous en aurons besoin pour, d'une part, vérifier la fonctionnalité de la chaßne d'outils, et d'autre part, nous l'utiliserons comme «donneur» de la configuration d'assemblage du projet principal.


Choisissez Fichier> Nouveau> Projet C / C ++. Sélectionnez C ++ Managed Build. Nous créons un projet de type hello world pour la chaßne d'outils Cygwin GCC:



Ensuite, vous devrez choisir les configurations d'assemblage à créer. Un simple débogage suffit.
Vous pouvez maintenant vérifier que le projet se déroule en choisissant Projet> Tout construire. Il est également conseillé de vérifier le débogage sous Cygwin en exécutant Exécuter> Déboguer en tant que> Application C / C ++ locale. L'application affichera «Hello world» sur la console à l'intérieur de CubeIDE.


Pour que le dĂ©bogueur affiche les lignes exĂ©cutables dans les fichiers de code source, vous devez configurer l'affichage des chemins. Dans la fenĂȘtre Window> Preferences, dans l'onglet C / C ++> Debug, sĂ©lectionnez Source Lookup Path et ajoutez un nouvel affichage: Add> Path Mapping. Dans la fenĂȘtre, vous devez nommer quelque chose comme un nouvel affichage et ajouter des lignes pour les disques qui sont dans le systĂšme:


  • \ cygdrive \ c - C: \
  • \ cygdrive \ g - G: \



Pour une belle exécution de test, nous avons également besoin d'un plug-in pour Eclipse avec prise en charge des tests unitaires pour C ++. Il est installé directement à partir de STM32CubeIDE: menu Aide> Installer un nouveau logiciel, puis sélectionnez le référentiel Eclipse et installez le plug-in C / C ++ Unit Testing Support.



Créer la bibliothÚque de tests Google


Le code source de la bibliothĂšque peut ĂȘtre rĂ©cupĂ©rĂ© Ă : https://github.com/google/googletest/tree/release-1.8.1
Décompressez les sources, accédez au répertoire googletest-release-1.8.1 à l'aide du terminal Cygwin et exécutez:


cmake . make 

Une fois l'assemblage rĂ©ussi, le fichier de bibliothĂšque statique sera dans ./googlemock/lib/libgtest.a et les fichiers d'en-tĂȘte seront dans le rĂ©pertoire ./googletest/include/gtest/. Ils devront ĂȘtre copiĂ©s dans notre projet (ou pour enregistrer le chemin d'accĂšs Ă  ces fichiers dans les paramĂštres du projet).


Création d'un projet pour STM32


Conception pour la carte de débogage STM32L476G-DISCO. L'exemple ne sera pas trop sophistiqué - il y a deux LED sur la carte, laissez-les afficher un compteur binaire de 00 à 11. Nous allons implémenter un module séparé pour le compteur, décrit dans une paire de fichiers .h et .c, et écrire un test pour cela.
Le projet peut ĂȘtre crĂ©Ă© comme d'habitude, en utilisant le configurateur Cube, l'essentiel est de s'assurer que les broches PB2 et PE8 sont configurĂ©es comme sorties numĂ©riques. Lors de la crĂ©ation d'un projet, il serait prĂ©fĂ©rable de spĂ©cifier le type - C ++, cela sera nĂ©cessaire pour compiler les tests (le code principal sera toujours compilĂ© par le compilateur C). La conversion d'un projet Ă  partir de C sera possible plus tard, en cliquant sur le nom du projet RMB et en sĂ©lectionnant «Convertir en C ++».


Pour la compilation sous MK et pour les tests, nous avons besoin de deux configurations d'assemblage diffĂ©rentes. Dans ces configurations, diffĂ©rents ensembles de fichiers seront collectĂ©s - les principaux obtiendront les modules pour travailler avec le matĂ©riel et les modules testĂ©s, et le test obtiendra les mĂȘmes modules testĂ©s et les mĂȘmes fichiers de test. Par consĂ©quent, nous crĂ©erons diffĂ©rents rĂ©pertoires Ă  la racine du projet - Application avec le code d'application pour MK (vous pouvez simplement renommer le rĂ©pertoire Src crĂ©Ă© par Cube), Commun pour les modules qui ne dĂ©pendent pas du fer (que nous testerons) et Tests pour les tests. Les rĂ©pertoires peuvent ĂȘtre exclus de l'assembly en cliquant sur RMB sur leur nom, menu Configuration des ressources> Exclure de la gĂ©nĂ©ration.


Ajoutez notre module compteur au répertoire commun:


Led_counter code

(led_counter.h):


 #ifndef LED_COUNTER_H_ #define LED_COUNTER_H_ #include <stdint.h> void Led_Counter_Init(); uint8_t Led_Counter_Get_Next(); #endif /* LED_COUNTER_H_ */ 

led_counter.cpp:


 #include "led_counter.h" static uint8_t led_cnt_state = 0; void Led_Counter_Init() { led_cnt_state = 0; } uint8_t Led_Counter_Get_Next() { if(++led_cnt_state > 3) led_cnt_state = 0; return led_cnt_state; } 

Les rĂ©pertoires Common et Tests doivent ĂȘtre ajoutĂ©s au chemin de recherche pour les fichiers include: propriĂ©tĂ©s du projet (PropriĂ©tĂ©s)> C / C ++ GĂ©nĂ©ral> Chemins et symboles> Inclut.


Ajouter au travail avec les LED principales


Fragment main.c

main.c:


 
 /* USER CODE BEGIN Includes */ #include "led_counter.h" /* USER CODE END Includes */ 
 int main(void) { 
 /* USER CODE BEGIN WHILE */ Led_Counter_Init(); uint8_t led_state = 0; while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ led_state = Led_Counter_Get_Next(); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, led_state & (1<<0)); HAL_GPIO_WritePin(GPIOE, GPIO_PIN_8, led_state & (1<<1)); HAL_Delay(500); } /* USER CODE END 3 */ 
 } 

Le projet doit ĂȘtre compilĂ© et exĂ©cutĂ©, et les voyants doivent clignoter.


Tests d'Ă©criture


Maintenant ce pour quoi tout a commencé.


Créez une nouvelle configuration de construction via les propriétés du projet - Propriétés> Construction C / C ++> ParamÚtres> Gérer les configurations. CubeIDE ne vous permet tout simplement pas de créer une configuration pour la construction sous Cygwin, alors copiez-la à partir du projet que nous avons créé précédemment:



Vous devez maintenant basculer vers cette configuration et configurer les chemins d'accĂšs aux fichiers source et aux fichiers d'en-tĂȘte. Dans les propriĂ©tĂ©s du projet dans l'onglet Chemins et symboles que nous prescrivons (lors de l'ajout d'une entrĂ©e, il est prĂ©fĂ©rable de mettre un daw dans le champ "ajouter Ă  toutes les langues"):


  • Comprend - Tests / Inc, Commun / Inc
  • BibliothĂšques - gtest
  • Chemins de bibliothĂšque - Tests / Lib
  • Emplacement source - / <prj_name> / Common et / <prj_name> / Tests (remplacez <prj_name> par le nom du projet)

Ensuite, copiez la bibliothĂšque gtest - le fichier .a dans le rĂ©pertoire Tests / Lib du projet et les fichiers d'en-tĂȘte dans le dossier gtest - dans le dossier Tests / Inc. Dans le dossier Tests, crĂ©ez un nouveau fichier main.cpp dans lequel les tests seront exĂ©cutĂ©s. Son contenu est standard:


main.cpp:


 /* * Unit tests main file */ #include "gtest/gtest.h" int main(int argc, char *argv[]) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } 

De plus, pour vĂ©rifier la configuration, nous allons crĂ©er un test qui vĂ©rifiera que la taille du pointeur est de 32 bits dans notre environnement (nous voulons nous assurer qu'il est le mĂȘme que sur le microcontrĂŽleur, pour cela nous avons dĂ©fini Cygwin 32 bits).


Créez le fichier de test test_platform.cpp suivant:


 #include "gtest/gtest.h" TEST(PlatformTest, TestPointerSize) { //Check pointer size is 32 bit ASSERT_EQ(sizeof(void*)*8, 32U); } 

Maintenant, si le projet est exécuté en tant qu'application C ++ normale, la sortie de débogage affichera un message de Google Test indiquant que tous les tests ont réussi.


La structure du projet devrait ressembler Ă  ceci:


Nous allons maintenant Ă©crire des tests pour notre module compteur LED. Les fichiers de test se trouvent dans le dossier Tests:


test_led_counter.cpp
 #include "gtest/gtest.h" extern "C" { #include "led_counter.h" } // Test fixture class LedCounterTest: public ::testing::Test { protected: void SetUp() { Led_Counter_Init(); } }; // Check initial value TEST_F(LedCounterTest, TestInitialValue) { Led_Counter_Init(); ASSERT_EQ(Led_Counter_Get_Next(), 1); } // Check how value is incremented TEST_F(LedCounterTest, TestIncrementValue) { Led_Counter_Init(); unsigned int val = Led_Counter_Get_Next(); for(int i=0;i<1;i++) { ASSERT_EQ(Led_Counter_Get_Next(), ++val); } } // Check how value return to 0 after 3 TEST_F(LedCounterTest, TestZeroCrossing) { Led_Counter_Init(); for(int i=0;i<3;i++) { Led_Counter_Get_Next(); } ASSERT_EQ(Led_Counter_Get_Next(), 0); } 

Pour que les rĂ©sultats du test soient affichĂ©s dans une belle fenĂȘtre, vous devez crĂ©er une nouvelle configuration de lancement dans le menu ExĂ©cuter> Configurations de dĂ©bogage. Le plugin installĂ© vous permet de crĂ©er des configurations de type C / C ++ Unit. CrĂ©ez-le, appelez ExĂ©cuter les tests, sĂ©lectionnez la configuration utilisĂ©e de l'assemblage «Test» et dĂ©cochez la case «ArrĂȘter au dĂ©marrage à» de l'onglet DĂ©bogueur. AprĂšs cela, la configuration peut ĂȘtre lancĂ©e.


Pour qu'une fenĂȘtre avec les rĂ©sultats apparaisse, sĂ©lectionnez-la dans FenĂȘtre> Afficher la vue> Autre> C / C ++> UnitĂ© C / C ++.



C'est fait! Maintenant, le projet peut ĂȘtre compilĂ© et exĂ©cutĂ© sous le MK cible comme d'habitude. Lorsque vous devez exĂ©cuter des tests locaux, lorsque vous exĂ©cutez la configuration ExĂ©cuter les tests, le projet est automatiquement reconstruit pour x86, l'environnement exĂ©cute les tests et affiche le rĂ©sultat.


Littérature


  1. J. Grenning. Développement piloté par les tests pour Embedded C. - travaux fondamentaux sur les tests unitaires des systÚmes embarqués et sur l'application de la méthodologie TDD.
  2. https://uncannier.com/unit-testing-of-embedded-firmware-part-1-software-confucius/ - Test unitaire du code du microcontrĂŽleur x86 au Texas Compments Studio Code Composer Studio, framework CppUTest
  3. http://blog.atollic.com/why-running-your-embedded-arm-cortex-code-on-a-host-pc-is-a-good-thing - un article expliquant pourquoi il pourrait ĂȘtre utile d'exĂ©cuter du code pour un microcontrĂŽleur sur une plateforme de bureau

Source: https://habr.com/ru/post/fr469367/


All Articles