Le test unitaire le plus simple, c’est de vérifier que son API publique n’a pas changé.
Ça veut dire :
- vérifier que les modules ont bien les mêmes définitions (un nom qui était importable n’a pas disparu).
- vérifier que les fonctions et méthodes ont bien la même signature (les arguments avec le même nom n’ont pas changé de place, et les keywords arguments n’ont pas changé de nom).
- vérifier que les classes ont le même nom, les mêmes méthodes publiques avec les mêmes signatures et les mêmes attributs.
Ce sont des tests super cons qui demandent d’écrire du code du genre :
class Foo: bar = True def __init__(self, stuff=False): self.stuff def thing(self): return "doh" # et dans les tests self.assertTrue(hasattr(Foo, 'bar')) self.assertTrue(hasattr(Foo, 'thing')) self.assertTrue(hasattr(Foo(), 'stuff')) |
Et personne ne le fait, car déjà les tests c’est relou, mais écrire des tautologies à la main, c’est au dela du tolérable.
Pourtant, ce genre de tests m’aurait déjà sauvé les gosses plusieurs fois. Une faute de frappe qui se glisse, un attribut qu’on rend privé, un méthode qu’on déplace et on pense avoir tout refactoré, un pote qui change un truc qu’on utilisait, etc.
Je me demandais donc si il existait un truc qui permette de faire :
self.assertStablePublicAPI("package.module") # scanne tout le module et tous les objets self.assertStablePublicAPI("package.module:Class") # check juste la classe self.assertStablePublicAPI("package.module:func") # check juste la function |
Le but étant que quand on lance les test, ça check si ça rencontre un nouvel objet/attribut/param et sauvegarde tout un dans un JSON. Aux prochains tests, si on a modifier l’API publique, le test foire jusqu’à ce qu’on modifie explicitement le fichier JSON.
On doit bien entendu pouvoir régler le truc pour ignorer ou ajouter explicitement des choses à checker, par exemple par défaut ça ignore tous les machins avec des underscores dans le nom.
J’ai cherché sur le net, mais j’arrive pas à trouver ça. Des pistes ?
Je ne sais pas, mais ce serait un générateur de “tautologies” :-)
Ca me dit rien du tout, mais j’aime beaucoup le concept.
J’avais commencé à utiliser une sorte d’introspection pour récupérer toutes les classes/fonctions disponibles dans Django, afin, a partir d’un nom, de déterminer le package a importer (https://github.com/romgar/django-import-seeker/blob/master/introspection.py, exemple d’utilisation sur http://djangois.youkidea.com). a la maniere d’un IDE qui importe automatiquement a partir d’un nom.
On ne serait pas si loin de ce que tu cherches non ? sauf que pour l’instant ça ne récupère que les classes/fonctions disponibles.
Ca fait un l’inverse non ? Prend une classe, et trouve un sous module d’un module qui le contient.
Ca ressemble à un analyseur statique de code (genre pylint/pyflake) mais à l’envers
Comme j’aime beaucoup l’idée, j’ai mis à profit ce 1er mai pour coder une poc :
https://github.com/touilleMan/samarche
Des volontaires pour me faire un retour ? ;-)
Ah, voilà une initiative sympas. Je vais de ce pas ouvrir des tickets.
EDIT : done. Y a moyen de faire un beau projet là.
Bon, ben voila le post qui m’aura finalement fait commenter ce blog.
Super initiative ! Je vais de ce pas forker ça !
@Sam le concept global oui c’est l’inverse, mais la recherche pour savoir si la classe est présente utilise une introspection (assez basique) pour récupérer les classes/fonctions disponibles. Enfin bref, rien de miraculeux, mais j’aime bien l’idée de test de l’API, je vais creuser aussi.
Ouai, j’ai vu, mais d’après ce que j’ai compris, ça prend toutes les classes et les fonctions du module, donc ça implique aussi les trucs importés dans le module ce qui est probablement pas ce qu’on veut. A mon avis il faudra utiliser le parseur ast pour obtenir ces infos, car difficile de filter un from bidule import * autrement.
Je suis étonné que personnne n’ai parlé de PyCharm. Il détecte ce genre d’erreur avec coloration syntaxique. Avec PyCharm, je ne me pose plus de questions sur les types, attributs, etc
Inutile d’exécuter le code Python pour détecter les erreurs.
Inutile de créer des tests unitaires de ce type.
Il existe sans doute des cas d’erreur que PyCharm ne détecte pas mais je ne les ai pas encore rencontré.
Le seul défaut que je lui trouve est le besoin d’une machine puissante, et encore on peut désactiver l’inspection de code automatique pour le lancer à la demande.
@tsez, commes les commentaires précédents sur le typage, tu passes à côté du problème. En effet, si tu modifies ton API publique et que tout ton code suit cette modification, pycharm ne lèvera aucune erreur. Tout ira bien pour lui car ton programme marchera très bien. Mais tu auras quand même cassé ton API publique, et donc tous les codes tierces partie qui utilise ton code. De plus, et même si on ne parle que de ton propre code, il suffit qu’une partie du projet qui utilise ce code ne soit pas ouvert pour que PyCharm n’y voit que du feu.
Je viens d’avoir exactement ce problème sur des applis que je développe.
J’ai ajouté une fonctionnalité à un package ‘lib’ et “réorganisé” pour mettre dans un module commun des fonction partagées.
Sauf que j’ai un package qui utilisait cette lib et utilisait cette fonction. Les tests n’ont rien vus parce que je testait avec la version ‘master’ de la lib, ça a pété après déploiement sur le serveur de test.
Même si je “savais” que bouger ça allait avoir un impact, aucun outil ne m’a confirmé “fais gaffe tu casses tout là”.