J'ai travaillé sur un système intégré cet été, écrit en C droit. Il s'agissait d'un projet existant que l'entreprise pour lequel je travaillais avait repris. Je me suis habitué à écrire des tests unitaires en Java à l'aide de JUnit, mais je ne savais pas quel était le meilleur moyen d'écrire des tests unitaires pour le code existant (qui nécessitait un refactoring) ainsi que pour l'ajout de nouveau code au système.
Existe-t-il un moyen de rendre le test de code en C simple aussi simple que le test de code Java avec, par exemple, JUnit? Toute idée qui s'appliquerait spécifiquement au développement intégré (compilation croisée sur une plate-forme arm-linux) serait grandement appréciée.
Un cadre de test unitaire en C est Check ; une liste des frameworks de tests unitaires en C peut être trouvée ici et est reproduite ci-dessous. Selon le nombre de fonctions de bibliothèque standard que votre environnement d’exécution a, vous pouvez ou non utiliser l’une d’elles.
AceUnit
AceUnit (Advanced C et Embedded Unit) se présente comme un cadre de test confortable des unités de code C. Il tente d'imiter JUnit 4.x et inclut des fonctionnalités de réflexion. AceUnit peut être utilisé dans des environnements à contraintes de ressources, par exemple. le développement de logiciels intégrés, et surtout, il fonctionne parfaitement dans les environnements où vous ne pouvez pas inclure un seul fichier d’en-tête standard ni appeler une seule fonction C standard à partir des bibliothèques ANSI/ISO C. Il a également un port Windows. Il n'utilise pas de fourches pour capter les signaux, bien que les auteurs se soient montrés intéressés par l'ajout d'une telle fonctionnalité. Voir le page d'accueil AceUnit .
GNU Autounit
Dans le même sens que Check, il est notamment interdit de lancer des tests unitaires dans un espace adresse séparé (en fait, l’auteur de Check a emprunté l’idée à GNU Autounit). GNU Autounit utilise abondamment GLib, ce qui signifie que la liaison et de telles options nécessitent des options spéciales, mais cela peut ne pas être un gros problème pour vous, en particulier si vous utilisez déjà GTK ou GLib. Voir le page d'accueil de GNU Autounit .
unité
Utilise également GLib, mais ne protège pas l'espace adresse des tests unitaires.
CUnit
Standard C, avec des plans pour une implémentation de l’interface graphique Win32. Ne branche pas ou ne protège pas actuellement l'espace d'adressage des tests unitaires. En début de développement. Voir le page d'accueil CUnit .
CuTest
Un framework simple avec un seul fichier .c et un fichier .h que vous déposez dans votre arborescence source. Voir le homepage de CuTest .
CppUnit
Le premier cadre de test unitaire pour C++; vous pouvez également l'utiliser pour tester le code C. Il est stable, activement développé et possède une interface graphique. Les principales raisons de ne pas utiliser CppUnit pour C sont d’abord parce qu’il est assez gros, et ensuite vous devez écrire vos tests en C++, ce qui signifie que vous avez besoin d’un compilateur C++. Si cela ne vous ressemble pas, cela vaut la peine d’être pris en compte, ainsi que d’autres frameworks de tests unitaires C++. Voir le page d'accueil CppUnit .
embUnit
embUnit (Embedded Unit) est un autre framework de test unitaire pour les systèmes embarqués. Celui-ci semble être remplacé par AceUnit. page d'accueil de l'unité intégrée .
MinUnit
Un ensemble minimal de macros et c’est tout! Le but est de montrer à quel point il est facile de tester votre code à l’unité. Voir le homepage MinUnit .
CUnit pour M. Ando
Une implémentation CUnit relativement nouvelle et apparemment encore en développement précoce. Voir le page d'accueil de CUnit for Mr. Ando .
Cette liste a été mise à jour pour la dernière fois en mars 2008.
CMocka est un framework de test pour C prenant en charge les objets fictifs. C'est facile à utiliser et à configurer.
Voir la page d'accueil de CMocka .
Criterion est un framework de test d’unités C multiplate-formes prenant en charge l’enregistrement automatique des tests, les tests paramétrés, les théories et pouvant produire dans plusieurs formats, notamment TAP et JUnit XML. Chaque test est exécuté selon son propre processus, de sorte que les signaux et les blocages peuvent être signalés ou testés si nécessaire.
Voir le page d'accueil du critère pour plus d'informations.
HWUT est un outil de test unitaire général très utile pour le langage C. Il peut aider à créer des Makefiles, à générer des scénarios de test volumineux codés dans un minimum de "tables d'itération", à parcourir des machines à états, à générer des stops C et plus. L'approche générale est assez unique: les verdicts sont fondés sur "bon stdout/mauvais stdout". La fonction de comparaison, cependant, est flexible. Ainsi, tout type de script peut être utilisé pour la vérification. Il peut être appliqué à n'importe quelle langue pouvant produire une sortie standard.
Voir la page d'accueil HWUT .
Un cadre de test unitaire multilingue, portable et moderne pour C et C++. Il offre une notation BDD optionnelle, une bibliothèque moqueuse, la possibilité de l'exécuter en un seul processus (pour faciliter le débogage). Un testeur qui découvre automatiquement les fonctions de test est disponible. Mais vous pouvez créer votre propre programme.
Toutes ces fonctionnalités (et plus) sont expliquées dans le manuel de CGreen .
Wikipedia donne une liste détaillée des frameworks de tests unitaires C sous Liste des frameworks de tests unitaires: C
Personnellement j'aime bien le framework de test Google .
La vraie difficulté à tester le code C consiste à casser les dépendances sur les modules externes afin que vous puissiez isoler le code en unités. Cela peut être particulièrement problématique lorsque vous essayez de tester le code hérité. Dans ce cas, je me retrouve souvent à utiliser l'éditeur de liens pour utiliser les fonctions de stubs dans les tests.
C’est ce à quoi les gens font référence quand ils parlent de " coutures ". En C, votre seule option est d’utiliser le pré-processeur ou l’éditeur de liens pour simuler vos dépendances.
Une suite de tests typique dans l'un de mes projets C pourrait ressembler à ceci:
#include "myimplementationfile.c"
#include <gtest/gtest.h>
// Mock out external dependency on mylogger.o
void Logger_log(...){}
TEST(FactorialTest, Zero) {
EXPECT_EQ(1, Factorial(0));
}
Notez que vous incluez réellement le fichier C et non le fichier d'en-tête . Cela donne l’avantage d’avoir accès à tous les membres de données statiques. Ici, je simule mon enregistreur (qui peut se trouver dans logger.o et donne une implémentation vide. Cela signifie que le fichier de test est compilé et lié indépendamment du reste de la base de code et exécuté séparément.
En ce qui concerne la compilation croisée du code, pour que cela fonctionne, vous avez besoin de bonnes installations sur la cible. J'ai fait cela avec googletest cross compilé à Linux sur une architecture PowerPC. Cela a du sens parce que vous avez un Shell complet et os pour rassembler vos résultats. Pour les environnements moins riches (que je qualifie de tout sans système d'exploitation complet), vous devez simplement créer et exécuter sur l'hôte. Vous devriez le faire quand même afin que vous puissiez exécuter les tests automatiquement dans le cadre de la construction.
Je trouve que tester du code C++ est généralement beaucoup plus facile du fait que OO le code est en général beaucoup moins couplé que procédural (bien sûr, cela dépend beaucoup du style de codage). Également en C++, vous pouvez utiliser des astuces telles que l'injection de dépendances et le remplacement de méthodes pour obtenir des coutures dans un code autrement encapsulé.
Michael Feathers a un excellent livre sur le test du code hérité . Dans un chapitre, il couvre les techniques pour traiter le code non-OO que je recommande fortement.
Edit : J'ai écrit un article de blog à propos du code de procédure des tests unitaires, avec source disponible sur GitHub .
Edit : Il existe un nouveau livre publié par les programmeurs pragmatiques qui traite spécifiquement du code C qui teste les unités et qui Je recommande fortement .
Minunit est un framework de tests unitaires incroyablement simple. Je l'utilise pour tester le code du microcontrôleur c pour avr.
J'utilise actuellement le framework de tests unitaires CuTest:
http://cutest.sourceforge.net/
Idéal pour les systèmes embarqués car très léger et simple. Je n'ai eu aucun problème à le faire fonctionner sur la plate-forme cible aussi bien que sur le bureau. En plus d'écrire les tests unitaires, tout ce qui est requis est:
Le système doit prendre en charge un tas et certaines fonctionnalités stdio (que tous les systèmes intégrés ne possèdent pas). Mais le code est assez simple pour que vous puissiez probablement utiliser des alternatives à ces exigences si votre plate-forme n'en dispose pas.
Grâce à une utilisation judicieuse des blocs extern "C" {}, il prend également en charge le test de C++.
Je dis presque la même chose que ratkok mais si vous avez une torsion intégrée aux tests unitaires, alors ...
nity - Cadre hautement recommandé pour les tests unitaires en code C.
Les exemples du livre mentionnés dans ce fil TDD pour C intégré sont écrits avec Unity (et CppUTest).
Vous voudrez peut-être aussi jeter un œil à libtap , un framework de test C qui génère le protocole TAP (Test Anything Protocol) et s’intègre ainsi parfaitement à toute une série d’outils issus de cette technologie. Il est principalement utilisé dans le monde des langages dynamiques, mais il est facile à utiliser et devient très populaire.
Un exemple:
#include <tap.h>
int main () {
plan(5);
ok(3 == 3);
is("fnord", "eek", "two different strings not that way?");
ok(3 <= 8732, "%d <= %d", 3, 8732);
like("fnord", "f(yes|no)r*[a-f]$");
cmp_ok(3, ">=", 10);
done_testing();
}
Il existe un cadre de test unitaire élégant pour C prenant en charge les objets fictifs appelé cmocka . Elle ne nécessite que la bibliothèque standard C, fonctionne sur diverses plates-formes informatiques (y compris intégrées) et avec différents compilateurs.
Il prend également en charge différents formats de sortie de message tels que les rapports Subunit, Test Anything Protocol et jUnit XML.
cmocka a été créé pour fonctionner également sur les plates-formes intégrées et prend également en charge Windows.
Un test simple ressemble à ceci:
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include <cmocka.h>
/* A test case that does nothing and succeeds. */
static void null_test_success(void **state) {
(void) state; /* unused */
}
int main(void) {
const struct CMUnitTest tests[] = {
cmocka_unit_test(null_test_success),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}
Le API est entièrement documenté et plusieurs exemples font partie du code source.
Pour commencer à utiliser cmocka, vous devriez lire l’article sur LWN.net: Test unitaire avec des objets fantaisie en C
cmocka 1.0 est sorti en février 2015.
Je n’étais pas allé trop loin en testant une ancienne application C avant de commencer à chercher un moyen de simuler des fonctions. J'avais besoin de moqueries pour isoler le fichier C que je veux tester des autres. J'ai essayé cmock et je pense que je vais l'adopter.
Cmock analyse les fichiers d'en-tête et génère des fonctions fictives en fonction des prototypes trouvés. Les simulacres vous permettront de tester un fichier C en parfaite isolation. Tout ce que vous avez à faire est de lier votre fichier de test avec des simulacres au lieu de vos fichiers d’objets réels.
Un autre avantage de cmock est qu’il validera les paramètres transmis aux fonctions simulées et vous permettra de spécifier la valeur de retour que les simulacres doivent fournir. Ceci est très utile pour tester différents flux d'exécution dans vos fonctions.
Les tests comprennent les fonctions typiques testA () et testB () dans lesquelles vous créez des attentes, appelez des fonctions pour tester et vérifier les assertions.
La dernière étape consiste à générer un coureur pour vos tests avec unité. Cmock est lié au cadre de test d'unité. L'unité est aussi facile à apprendre que tout autre framework de test unitaire.
Vaut la peine d'essayer et assez facile à comprendre:
http://sourceforge.net/apps/trac/cmock/wiki
Mise à jour 1
Cmockery est un autre cadre sur lequel j’enquête.
http://code.google.com/p/cmockery/
C'est un framework C pur supportant les tests unitaires et les moqueries. Il n'a pas de dépendance sur Ruby (contrairement à Cmock) et très peu sur les bibliothèques externes.
La configuration des simulacres nécessite un peu plus de travail manuel car elle ne génère pas de code. Cela ne représente pas beaucoup de travail pour un projet existant, car les prototypes ne changeront pas beaucoup: une fois que vous avez vos simulacres, vous n’aurez plus besoin de les changer pendant un moment (c’est mon cas). La frappe supplémentaire permet un contrôle complet des simulacres. S'il y a quelque chose que vous n'aimez pas, vous changez simplement votre maquette.
Pas besoin d'un coureur de test spécial. Il vous suffit de créer un tableau de tests et de le transmettre à une fonction run_tests. Un peu plus de travail manuel ici aussi, mais j'aime bien l'idée d'un cadre autonome autonome.
De plus, il contient quelques astuces géniales que je ne connaissais pas.
Globalement Cmockery a besoin d’un peu plus de compréhension des simulacres pour commencer. Des exemples devraient vous aider à surmonter cela. Il semble que cela puisse faire le travail avec des mécaniciens plus simples.
En tant que débutant en C, j’ai trouvé les diapositives appelées . Le développement piloté par les tests en C très utile. Fondamentalement, il utilise la assert()
standard avec &&
pour remettre un message, sans aucune dépendance externe. Si quelqu'un est habitué à une infrastructure de test de pile complète, cela ne fonctionnera probablement pas :)
Je n'utilise pas de framework, j'utilise simplement le support cible "check" d'autotools. Implémentez un "principal" et utilisez assert (s).
Mon test dir Makefile.am (s) ressemble à:
check_PROGRAMS = test_oe_amqp
test_oe_amqp_SOURCES = test_oe_amqp.c
test_oe_amqp_LDADD = -L$(top_builddir)/components/common -loecommon
test_oe_amqp_CFLAGS = -I$(top_srcdir)/components/common -static
TESTS = test_oe_amqp
Il y a CUnit
Et Unité intégrée est un cadre de test unitaire pour Embedded C System. Sa conception a été copiée à partir de JUnit et CUnit et plus, puis légèrement adaptée pour Embedded C System. L'unité intégrée ne nécessite pas de bibliothèques C standard. Tous les objets sont alloués à la zone const.
Et Tessy automatise les tests unitaires des logiciels embarqués.
Nous avons écrit CHEAT (hébergé sur GitHub ) pour une utilisation et une portabilité faciles.
Il n'a pas de dépendances et ne nécessite aucune installation ou configuration. Seul un fichier d'en-tête et un scénario de test sont nécessaires.
#include <cheat.h>
CHEAT_TEST(mathematics_still_work,
cheat_assert(2 + 2 == 4);
cheat_assert_not(2 + 2 == 5);
)
Les tests sont compilés dans un exécutable qui prend en charge l'exécution des tests et rend compte de leurs résultats.
$ gcc -I . tests.c
$ ./a.out
..
---
2 successful of 2 run
SUCCESS
Il a aussi de jolies couleurs.
Le livre de Michael Feather intitulé "Travailler efficacement avec le code hérité" présente de nombreuses techniques spécifiques aux tests unitaires au cours du développement du C.
Il existe des techniques liées à l'injection de dépendance spécifiques au C que je n'ai jamais vues ailleurs.
CppUTest - Cadre hautement recommandé pour les tests unitaires en code C.
Les exemples dans le livre qui est mentionné dans ce fil TDD pour C intégré sont écrits en utilisant CppUTest.
autre que mon parti pris évident
http://code.google.com/p/seatest/
est un moyen simple et agréable de tester le code C. imite xUnit
J'utilise CxxTest pour un environnement incorporé c/c ++ (principalement C++).
Je préfère CxxTest car il a un script Perl/python pour construire le lanceur de test. Après une petite pente pour l'installer (plus petit encore puisque vous n'avez pas à écrire le testeur), il est assez facile à utiliser (inclut des exemples et une documentation utile). Le plus gros travail consistait à configurer le "matériel" auquel le code accède afin que je puisse tester les unités/modules efficacement. Après cela, il est facile d’ajouter de nouveaux cas de tests unitaires.
Comme mentionné précédemment, il s’agit d’un framework de test unitaire C/C++. Vous aurez donc besoin d’un compilateur C++.
Après avoir lu Minunit, j’ai pensé qu’une meilleure façon de procéder était de fonder le test en macro d’affirmation, que j’utilise beaucoup comme technique de programme défensif. J'ai donc utilisé la même idée de Minunit mélangée à une affirmation standard. Vous pouvez voir mon framework (un bon nom pourrait être NoMinunit) dans blog de k0ga
Google dispose d'un excellent cadre de test. https://github.com/google/googletest/blob/master/googletest/docs/primer.md
Et oui, autant que je sache, cela fonctionnera avec du C ordinaire, c’est-à-dire qu’il n’exige pas de fonctionnalités C++ (peut nécessiter un compilateur C++, pas sûr).
cmockery à http://code.google.com/p/cmockery/
Cmockery est un projet récemment lancé qui consiste en une bibliothèque C très simple à utiliser pour l'écriture de tests unitaires.
Tout d’abord, regardez ici: http://en.wikipedia.org/wiki/List_of_unit_testing_frameworks#C
Ma société a une bibliothèque C utilisée par nos clients. Nous utilisons CxxTest (une bibliothèque de tests unitaires C++) pour tester le code. CppUnit fonctionnera également. Si vous êtes coincé en C, je recommanderais RCUNIT (mais CUnit est bien aussi).
essayez lcut! - http://code.google.com/p/lcut
API Sanity Checker - Framework de test pour les bibliothèques C/C++:
Un générateur automatique de tests unitaires de base pour une bibliothèque partagée C/C++. Il est capable de générer des données d'entrée de paramètres raisonnables (dans la plupart des cas, mais malheureusement pas dans tous les cas) et de composer des cas de test simples (de "qualité" ou "superficielle") pour chaque fonction de l'API via l'analyse des déclarations contenues dans l'en-tête. des dossiers.
La qualité des tests générés permet de vérifier l'absence d'erreurs critiques dans des cas d'utilisation simples. L'outil est capable de construire et d'exécuter des tests générés et de détecter des plantages (segfaults), des abandons, toutes sortes de signaux émis, des codes de retour de programmes non nuls et des suspensions de programmes.
Exemples:
J'ai utilisé RCUNIT pour effectuer quelques tests unitaires du code intégré sur PC avant de tester sur la cible. Une bonne abstraction de l’interface matérielle est importante, sinon l’endianisme et les registres mappés en mémoire vont vous tuer.
Si vous connaissez JUnit, je vous recommande CppUnit. http://cppunit.sourceforge.net/cppunit-wiki
En supposant que vous disposiez du compilateur c ++ pour effectuer les tests unitaires. sinon, je suis d’accord avec Adam Rosenfield pour dire que c’est ce que vous voulez.
LibU ( http://koanlogic.com/lib ) possède un module de test unitaire qui permet les dépendances explicites de la suite/du cas de test, l'isolation de test, l'exécution en parallèle et un formateur de rapport personnalisable (les formats par défaut sont xml et txt ).
La bibliothèque est sous licence BSD et contient de nombreux autres modules utiles - mise en réseau, débogage, structures de données couramment utilisées, configuration, etc. - si vous en avez besoin dans vos projets ...
Je suis surpris que personne ne mentionne Cutter (http://cutter.sourceforge.net/) ) Vous pouvez tester C et C++, il s'intègre de manière transparente à autotools et propose un didacticiel vraiment sympa.
Une technique à utiliser consiste à développer le code de test unitaire avec un framework C++ xUnit (et un compilateur C++), tout en conservant la source du système cible sous la forme de modules C.
Assurez-vous de compiler régulièrement votre source C sous votre compilateur croisé, automatiquement avec vos tests unitaires si possible.
Si vous êtes toujours à la recherche de structures de test, CUnitWin32 en est une pour la plate-forme Win32/NT.
Cela résout un problème fondamental que j'ai rencontré avec d'autres frameworks de test. A savoir, les variables globales/statiques sont dans un état déterministe car chaque test est exécuté en tant que processus séparé.
Si vous ciblez les plates-formes Win32 ou le mode noyau NT, vous devriez jeter un œil à cfix .
Je viens d'écrire Libcut par frustration avec les bibliothèques de tests d'unités C existantes. Il possède une chaîne de types automatique de primitives (nul besoin de test_eq_int, test_eq_long, test_eq_short, etc ...; seuls deux ensembles différents pour les primitives et les chaînes) et se compose d'un fichier d'en-tête. Voici un court exemple:
#include <libcut.h>
LIBCUT_TEST(test_abc) {
LIBCUT_TEST_EQ(1, 1);
LIBCUT_TEST_NE(1, 0);
LIBCUT_TEST_STREQ("abc", "abc");
LIBCUT_TEST_STRNE("abc", "def");
}
LIBCUT_MAIN(test_abc);
Cela fonctionne seulement avec C11, cependant.