Supposons que j'implémente quelque chose de simple comme la recherche dans une liste / un tableau trié. La fonction (en c #) ressemblerait à:
static int FindIndex(int[] sortedList, int i);
Je pourrais implémenter et tester cela en termes de fonctionnalités, mais pour des raisons évidentes, je préférerais généralement une recherche binaire à une recherche linéaire ou quelque chose d'intentionnellement stupide.
Ma question est donc la suivante: faut-il tenter d'écrire des tests qui garantissent des performances en termes de complexité algorithmique et si oui, comment?
J'ai commencé à faire des arguments des deux côtés de la partie «devriez-vous» de cette question, mais j'aimerais voir ce que les gens disent sans mes arguments pour les inciter.
En termes de "comment", cela devient très intéressant :) Vous pouvez voir paramétrer l'opérateur de comparaison et avoir un test dont l'opérateur de comparaison compte les comparaisons ou quelque chose comme ça. Mais ce n'est pas parce que vous le pouvez que vous devriez ...
Quelqu'un d'autre a-t-il envisagé cela (probablement)? Merci.
la source
Réponses:
La complexité algorithmique est une construction théorique et en tant que telle, elle est mieux «testée» avec un crayon et du papier. Il ne peut pas être utilement testé mécaniquement.
Les performances absolues peuvent être testées mécaniquement et peuvent faire des tests unitaires utiles. Si les performances sont importantes, vous pouvez spécifier un seuil: "cette requête ne devrait pas prendre plus de 50 ms pour s'exécuter sur 10 6 numéros, et pas plus de 60 ms sur 10 7 numéros". Pour lequel vous pouvez créer un test unitaire.
L'utilisateur final ne se soucie pas de savoir si votre algorithme est linéaire ou logarithmique; ils se soucient de savoir si leur interface utilisateur répond toujours instantanément, même s'ils disposent d'un an de données dans l'application.
la source
Bien que je ne sois pas sûr que cet outil soit particulièrement utile pour les tests unitaires, l'article "Empirical Computational Complexity" par Goldsmith, Aiken et Wilkerson décrit une méthode pour instrumenter le code et observer son comportement dynamique sur un ensemble de diverses entrées à empiriquement dériver sa complexité asymptotique. Le programme décrit dans l'article est open-source et est disponible ici .
J'espère que cela t'aides!
la source
L'essentiel est de l'essayer avec des données volumineuses et de voir si cela prend trop de temps.
Dans mon expérience de réglage des performances, comme dans cet exemple , ce qui se passe, c'est que si un algorithme est (par exemple) O (n ^ 2), cela peut être très bien tant que le pourcentage de temps qu'il faut ne parvient jamais au radar.
Cependant, quand on lui donne un ensemble de données d'une taille qui pourrait ne pas être vue mais une fois par an, la fraction du temps total aspiré par cet algorithme peut devenir catastrophiquement dominante.
Si vous pouvez y arriver en test, c'est une très bonne chose, car il est extrêmement facile de trouver le problème, comme s'il s'agissait d'une boucle infinie réelle.
la source
Je ne pense pas que ce que vous voulez faire soit des tests unitaires.
AFAIK, les tests unitaires visent uniquement à s'assurer que le code fait ce qu'il doit faire et qu'il ne se concentre pas sur les performances.
Il existe d'autres types d'outils et de modèles pour mesurer les performances. Je me souviens maintenant de l'un des tests d'acceptation axés sur les exigences non fonctionnelles.
Il y en a peu d'autres comme les tests de performances (qui utilisent des tests de stress, des tests de charge, etc.).
Vous pouvez également utiliser certains outils de stress avec un outil de construction (fourmi, studio de construction automatisé) dans le cadre de vos étapes de déploiement (c'est ce que je fais).
Donc, la réponse courte est non, vous ne devriez pas vous en soucier lorsque vous testez un code à l'unité.
la source
Passer le comparateur et garder cette trace du nombre d'appels fonctionnera à des fins simples telles que vérifier que le nombre de comparaisons lors d'une recherche dans une entrée fixe (disons
new int[] { 1,2,3, ... , 1024 }
) reste inférieur à 10. Cela va au moins expliquez clairement vos intentions sur le comportement de l'algorithme.Je ne pense pas que les tests unitaires soient la bonne voie à suivre pour vérifier que votre algorithme est O (log n); cela nécessiterait beaucoup de génération de données aléatoires, un ajustement de courbe et probablement des statistiques noueuses pour déterminer si un groupe de points de données correspond à l'exécution attendue. (Pour cet algorithme, c'est probablement faisable, mais si vous commencez à trier, etc., il deviendra difficile de frapper de manière répétée les pires scénarios).
la source