Je vais donner une conférence à mon département la semaine prochaine sur les tests unitaires et le développement piloté par les tests. Dans le cadre de cela, je vais montrer des exemples concrets à partir d'un code que j'ai écrit récemment, mais je voudrais également montrer quelques exemples très simples que j'écrirai dans l'exposé.
J'ai cherché sur le Web de bons exemples, mais j'ai eu du mal à en trouver qui soient particulièrement applicables à notre domaine de développement. Presque tous les logiciels que nous écrivons sont des systèmes de contrôle profondément intégrés fonctionnant sur de petits microcontrôleurs. Il y a beaucoup de code C qui est facilement applicable aux tests unitaires (je parlerai de tests unitaires sur le PC plutôt que sur la cible elle-même) tant que vous restez à l'écart de la couche `` inférieure '': ce qui parle directement aux périphériques du microcontrôleur. Cependant, la plupart des exemples que j'ai trouvés ont tendance à être basés sur le traitement de chaînes (par exemple, l'excellent Dive Into Python chiffres romains) et comme nous n'utilisons presque jamais de chaînes, cela ne convient pas vraiment ( les seules fonctions de bibliothèque que notre code utilise généralement sont memcpy
, memcmp
et memset
, donc quelque chose basé sur strcat
ou des expressions régulières n'est pas tout à fait correct) .
Donc, passons à la question: s'il vous plaît, quelqu'un peut-il offrir de bons exemples de fonctions que je peux utiliser pour démontrer les tests unitaires dans une session en direct? Une bonne réponse à mon avis (sous réserve de modifications) serait probablement:
>
plutôt que >=
) qui est facile à mettre en place et qui fonctionnerait toujours dans la plupart des cas, mais qui romprait avec certains cas Edge particuliers: facile à identifier et à corriger avec un test unitaire.Des pensées?
Bien que ce ne soit probablement pas pertinent, les tests eux-mêmes seront probablement écrits en C++ à l'aide de Google Test Framework: tous nos en-têtes ont déjà le #ifdef __cplusplus extern "C" {
envelopper autour d'eux; cela a bien fonctionné avec les tests que j'ai effectués jusqu'à présent.
Voici une fonction simple qui est censée générer une somme de contrôle sur len octets.
int checksum(void *p, int len)
{
int accum = 0;
unsigned char* pp = (unsigned char*)p;
int i;
for (i = 0; i <= len; i++)
{
accum += *pp++;
}
return accum;
}
Il a un bogue fencepost: dans l'instruction for, le test doit être i < len
.
Ce qui est amusant, c'est que si vous l'appliquez à une chaîne de texte comme celle-ci ...
char *myString = "foo";
int testval = checksum(myString, strlen(myString));
vous obtiendrez la "bonne réponse"! C'est parce que l'octet supplémentaire qui a été additionné est le terminateur de chaîne zéro. Vous pouvez donc finir par mettre cette fonction de somme de contrôle dans le code, et peut-être même l'envoyer avec, et ne jamais remarquer de problème - c'est-à-dire jusqu'à ce que vous commenciez à l'appliquer à autre chose que des chaînes de texte.
Voici un test unitaire simple qui signalera ce bug (la plupart du temps ... :-)
void main()
{
// Seed the random number generator
srand(time(NULL));
// Fill an array with junk bytes
char buf[1024];
int i;
for (i = 0; i < 1024; i++)
{
buf[i] = (char)Rand();
}
// Put the numbers 0-9 in the first ten bytes
for (i = 0; i <= 9; i++)
{
buf[i] = i;
}
// Now, the unit test. The sum of 0 to 9 should
// be 45. But if buf[10] isn't 0 - which it won't be,
// 255/256 of the time - this will fail.
int testval = checksum(buf, 10);
if (testval == 45)
{
printf("Passed!\n");
}
else
{
printf("Failed! Expected 45, got %d\n", testval);
}
}
Qu'en est-il de l'implémentation d'une fonction de tri comme tri à bulles ? Une fois que la fonction de tri fonctionne, vous pouvez continuer avec recherche binaire qui est tout aussi bon pour introduire les tests unitaires et TDD.
Le tri et la recherche dépendent de comparaisons qui sont faciles à se tromper. Cela implique également d'échanger des pointeurs autour desquels il faut procéder avec précaution. Les deux sont sujets aux erreurs, alors n'hésitez pas à gâcher :)
Quelques idées supplémentaires:
qsort
, et les tests devraient toujours réussir, prouvant que votre nouvelle fonction de tri fonctionne également.