11
votes

Comment rédiger des tests d'unité pour des fonctions qui s'appuient sur des données dynamiques?

permet de dire que vous avez un site Web, qui utilise une fonction pour récupérer des données de la base de données et renvoie le résultat à afficher / analysé / etc ...

Étant donné que les données extraites de la base de données sont dynamiques et pourraient potentiellement changer chaque seconde de la journée, comment écrivez-vous correctement un test d'unité pour cette fonction?

Disons que la fonction est censée renvoyer une gamme de résultats. Évidemment, un test unitaire pourrait être testé pour voir si un tableau est renvoyé ou non. Mais que se passe-t-il lorsque le contenu de la matrice elle-même est incorrect en raison d'une requête mysql incorrecte? La taille de la matrice pourrait être nulle ou que le contenu de la matrice pourrait être incorrect. Comme il s'appuie sur des données en constante évolution, comment le test de l'unité serait-il savoir ce qui est correct et que n'est pas? Des appels à la base de données de l'unité de base de l'unité lui-même soient nécessaires afin qu'il y ait quelque chose à comparer à?

Comment écrivez-vous correctement un test d'unité pour des fonctions qui s'appuient sur des données dynamiques?


1 commentaires

Cela pourrait être intéressant: blog.schauderhaft.de/2011/03/13/...


6 Réponses :


1
votes

Vous ne pouvez pas, vraiment. Vous aurez besoin d'un ensemble de données statique garanti pour créer des tests d'unité fiables. Peut-être qu'un instantané de base de données fonctionnera pour vous.

Les données dynamiques peuvent être utiles d'une autre manière, telles que l'effectuer des tests de régression ...


0 commentaires

1
votes

La plupart des tests se concentrent sur les chemins logiques impliqués dans des éléments tels que l'obtention de données. Pas sur la validité des données elle-même. La validité des données n'est significative que si votre application est en quelque sorte calculer ou y agréger, dans laquelle vous devriez pouvoir contrôler les entrées et vérifier que les résultats sont corrects.

Cela dit, vous souhaitez parfois toucher la même base de données que votre application utilise pour vérifier les retours. Par exemple, si vous testez une fonction qui renvoie une carte de données filtrée, votre test d'unité pourrait effectuer la même requête, puis effectuer une comparaison de ligne par ligne de chaque touche primaire des enregistrements et vérifiez que votre fonction a renvoyé le même ensemble de données que vous attendiez.

Je ne sais pas si c'est votre question spécifique, mais il n'ya rien de mal à frapper la base de données pour effectuer des revendications dans des tests unitaires, au contraire. Au moins je le fais tout le temps et personne n'a essayé de me faire arrêter :)


0 commentaires

10
votes

Les tests unitaires, sous leur forme idéale, ne devraient que tester une seule chose. Dans ce cas, vous testez deux choses:

  1. la logique de votre fonction
  2. la récupération de la base de données

    Je vais donc suggérer le refacteur suivant:

    1. Déplacez la logique de récupération de la base de données dans une fonction distincte
    2. avez la fonction que vous souhaitez tester appeler cette autre fonction
    3. Magisserie de la fonction qui renvoie des données afin que vous puissiez tester une seule fois la logique de votre application
    4. Si cela a du sens (si vous comptez sur une autre bibliothèque pour le faire, espérons-le que liber des tests), écrivez un test d'unité pour la fonction de récupération dynamique, où vous ne pouvez pas tester des spécificités, mais peut tester la structure et le caractère raisonnable des données renvoyées (par exemple, il dispose de tous les champs définis et est une heure dans les 5 secondes suivant maintenant).

      Également, c'est généralement une bonne idée d'exécuter des tests d'unité dans un environnement de test où vous avez un contrôle complet sur ce qui est stocké dans la base de données. Vous ne voulez pas les exécuter contre les données de production.


4 commentaires

Bons points. Vous dites donc que nous devrions rechercher uniquement la logique de nos fonctions de récupération de données, et non si les données récupérées sont correctes ou non? En outre, dans notre environnement de développement, nous faisons généralement une synchronisation à sens unique de notre DB en direct -> Dev DB afin que nous travaillions avec des données récentes. Dans tous les cas, les données sont toujours dynamiques. Merci.


Sur le niveau de l'unité, j'ai tendance à préférer tester que ma logique pour ce que j'écris à la DB est correcte, ainsi que ma logique pour ce que je fais avec mes lectures. Je n'ai pas besoin d'appuyer sur SQL SQL contre la base de données, sauf si j'utilise une ormission personnalisée que j'ai construite. Ensuite, je vais généralement écrire des tests fonctionnels ou d'intégration qui montrent que mes données sont ce que je m'attends à ce que ce soit. Effectuez ceux-ci contre une DB qui n'est pas mise à jour par rien d'autre que les tests. La simulation de scénarios mondiaux réels avec des données dynamiques convient à des tests d'intégration (et de performance), mais la confiance dans le système devrait provenir des autres.


Comment vous moquez-vous d'une fonction?


@RODRIGORUIZ Dans ce cas, se moquent de faire référence au processus d'encombrement d'une définition de fonction avec une fausse implémentation (et éventuellement testant qu'il a été appelé avec les bons paramètres pour en faire un véritable mock et pas seulement un talon - voir martinfowler.com/articles/mocksarentstuts.html ). Comment se moquer réellement d'une fonction dépend de la langue et du cadre de test que vous utilisez et constituerait une bonne question Stackoverflow si vous ne trouvez pas beaucoup d'informations sur votre langue / votre cadre de choix.



1
votes

Ignorer le fait que vous parlez de la DB, je pense que vous recherchez des tests d'unité pour couvrir chaque éventualité où, comme cela peut conduire à des rendements décroissants. Si j'étais vous, je couvrirais un chemin standard, puis quelques cas de bord. Le fait est que vous ne pouvez pas tout tester de manière pragmatique.

Voici quelques autres lisant

http://37signals.com/svn/posts/3159 -Testing-like-the-Tsa
Quelle est la profondeur de vos tests d'unité?
http://johnnosnose.blogspot.co.uk/2012/ 04 / ré-sur-test.html
http://martinfowler.com/bliki/testcoverage.html

Regarder votre problème associé à SpeciFc DB, pour tester cette fonction, vous devez probablement créer un Seam pour prépayer les données afin que vous puissiez couvrir ces cas.


1 commentaires

Heh dans mon expérience La plupart des bugs se glissent avec précision dans les zones difficiles à tester - et il semblerait donc que ce soient les seuls domaines qui bénéficient vraiment d'un investissement temporel dans un cadre de test. Les gestionnaires voient que je suis sûr et pensez-vous, "nous avons juste besoin de plus de tests unitaires pour X, Y Z" en fait "X", "Y", et "Z" sont essentiellement définis par la caractéristique d'être presque intense. Pour ces raisons, je considère que les tests de l'unité sont à peine plus flexibles que les pratiques de OUOP les plus rigides et non agiles à l'UML. En tant que développeur solo travaillant par heure, il s'agit vraiment d'un travail pour une balle d'argent.



2
votes

Si votre fonction ne intéressant quelque chose au-delà de tirer les données de la base de données, vous devez extraire la récupération dans une fonction différente et se moquer, de sorte que vous pouvez tester le reste.

Cela vous laisse encore la tâche de tester l'accès à la base. si elle envoie l'instruction SQL que vous pensez qu'il devrait, mais pas si l'instruction SQL fonctionne en fait, vous ne pouvez pas vraiment faire un test unitaire pour cela, parce que cela par définition pas accéder à tout db et vous pouvez simplement tester.

Vous avez besoin d'une base de données

Vous avez plusieurs optiones:

1) créer une base de données fixe pour ces tests qui ne soit pas changé par les tests.

Pro: Conceptuellement facile Con: difficile à maintenir. Les tests deviennent interdépendants, car ils reposent sur les mêmes données. Pas moyen de trucs de test qui fait les mises à jour, insertions ou suppressions (encore moins LDD)

2) créer une base de données au cours de votre test. Maintenant, vous avez deux problèmes: la mise en place de la base de données pour le test et le remplir avec des données .

Mise en place:

1) ont un serveur de base de données en cours d'exécution, avec un utilisateur / schéma / base de données pour erveryone qui a besoin d'exécuter des tests (au moins + devs ci-serveur). Schéma peut se créer en utilisant des trucs comme mise en veille prolongée ou les scripts que vous utilisez pour le déploiement.

fonctionne très bien, mais les lecteurs démodées DBAs fou. L'application ne doit pas dépendre du nom du schéma. Vous pourrez également rencontrer des problèmes lorsque vous avez plus d'un schéma utilisé par l'application. Cette configuration est assez lent. Il peut aider à mettre en sur des disques rapides. Comme les disques RAM

2) Avoir une base de données dans la mémoire. Facile à démarrer à partir du code et rapide. Mais dans la plupart des cas, il se comportera de la même chose que votre base de données de production. Ceci est moins préoccupante si vous utilisez quelque chose qui essaie de cacher la différence. J'utilise souvent une base de données dans la mémoire pour la première étape de construction et la vraie chose dans une deuxième étape.

Chargement du testdata

1) les gens me disent utiliser DBUnit. Je ne suis pas convaincu qu'il semble y avoir beaucoup de XML et difficile à maintenir lorsque le changement de colonnes ou de contraintes.

2) Je préfère code d'application normale. (Java + Hibernate) dans mon cas, mais le code qui vous écrit des données dans la base de données de la production devrait dans de nombreux cas être adapté pour écrire des données de test pour votre test. Il permet d'avoir une petite API spéciale qui cache les détails de satisfaire toutes les clés étrangères et d'autres choses: http://blog.schauderhaft.de/2011/03/13/testing-databases-with-junit-and-hibernate -part-1-one à la règle-les /


0 commentaires

1
votes

Je construirais les données dans le test lui-même. De cette façon, vous pouvez même tester des scénarios compliqués pour les données en constante évolution. Le point clé est que vous pouvez contrôler les modifications de données dans vos tests en ayant un test de test dédié,

Étape 1: Insérez les données dont vous avez besoin dans une DB utilisée uniquement par le test Étape 2: La DB est maintenant dans un état prévisible stable, de sorte que vous pouvez exécuter vos requêtes et tester la sortie


0 commentaires