PC & Mobile

TDD ne devrait pas être TDDious – Vers la science des données

TDD ne devrait pas être TDDious - Vers la science des données


Je rencontre encore le vieux débat sur le «comment tester», mais pouvons-nous nous amuser à tester des choses?

Je travaille comme ingénieur depuis plus de dix ans maintenant et je rencontre toujours le vieux débat sur le «test». Je suis ingénieur principal et cela signifie travailler avec mon équipe sur la façon dont nous construisons les choses. Je suis donc toujours ouvert aux points de vue opposés. Mais un sujet qui m’intéresse beaucoup est de savoir si nous devons utiliser Test Driven Development ou TDD. Et je pense que cela découle d'une incompréhension fondamentale sur la raison pour laquelle vous devriez apprécier le TDD et non le ressentir…

TDD me permet de comprendre le code que je devrais écrire, d’une manière claire et ciblée.

Pour moi, TDD est amusant. J'aime coder avec des tests de conduite et je ne peux pas imaginer pourquoi quelqu'un voudrait coder autrement. Je suis triste de ne pas savoir comment écrire un test soigné pour quelque chose. Et cela nous amène au premier grief habituel avec TDD: "Je ne peux pas simplement coder". Ce qui est intéressant dans la mesure où TDD me permet de comprendre le code que je devrais écrire de manière claire et ciblée. Sans cela, je peux me perdre dans les cas critiques ou dans la refactorisation à laquelle je n’avais pas pensé. L’autre chose est que TDD me permet en fait de «coder uniquement», car je peux écrire tout code terrifiant que j’aime, tant que le test réussit. Cette liberté est incroyable! J'écris un code terrible pour réussir un test, tester mes hypothèses, prouver ma méthode ou voir si je peux trop optimiser. Prenons un exemple de connexion à une base de données:

from mocks import mock_databasedef test_query_database ():
attendu_client = {
'id': 32,
'name': 'woof'
}
mock_database ()
client = get_customer ('woof')
assert client == attendu_client

Ce qui pourrait être mis en œuvre de plusieurs façons. J'ai vite mis cela ensemble:

base de données d'importationdef get_customer (utilisateur):
return database.connect (). query (f'SELECT id, nom FROM clients WHERE nom = "{utilisateur}" '). fetch ()

TDD me permet de me concentrer sur ce que je souhaite obtenir avec mon code. Après le cycle de Red -> Green -> Refactor, je peux revenir à tout moment pour rendre le code plus net:

base de données d'importationcustomer_query = 'SELECT ID, nom FROM clients WHERE name = "{}"'def get_customer (utilisateur):
conn = database.connect ()
curseur = conn.query (customer_query.format (utilisateur))
retourne curseur.fetch ()

Les tests vous donnent un filet de sécurité, que la fonctionnalité que vous avez écrite auparavant est toujours en cours d'exécution et fonctionne.

Cela prouve l’idée de réécrire votre code une fois les tests passés. J'applique souvent une approche de suppression à cela; si je peux supprimer le code et que les tests réussissent encore, je pourrai le reformuler avec plaisir. J’ai également utilisé cette technique comme outil d’enseignement pour montrer aux gens la quantité de code supplémentaire qu’ils écrivent. La suppression de code permet de prouver qu’il est inutile ou que les métriques de couverture sont trompeuses. Travaillant avec un état d'esprit agile consistant à «maximiser le travail non effectué», vous devez écrire le moins de code possible pour un test. Cette réduction constante du code est thérapeutique et constitue en soi un jeu qui ajoute au plaisir! Sachez qu'il est possible que le code soit trop coûteux à tester; Par exemple, nous initialisons des infrastructures en dehors d'une fonction de gestionnaire AWS Lambda. Cette initialisation est plus difficile à tester que le gestionnaire car il s’exécute à l’import. Il existe donc un contexte pour la suppression de code, mais en général, une couche de tests peut tout couvrir.

Ce qui est excitant, si je ne refactorise pas tout de suite, c’est qu’après quelques tests, mon code peut encore être assez mauvais. Le refactoring ne doit pas toujours avoir lieu après chaque test. Les tests vous donnent un filet de sécurité, que la fonctionnalité que vous avez écrite auparavant est toujours en cours d'exécution et fonctionne. Vous pouvez continuer sur la voie qui mène à sa conclusion naturelle, sans vous soucier d'autres choses qui ne se brisent pas ou du refactor en profondeur que vous devez faire plus tard. En évaluant le code et en supprimant autant que vous le pouvez, vous pouvez modifier de manière agressive de grandes quantités de données avec des tests qui vous protègent.

Un autre grief commun est «je dois changer tous les tests» lors d'un changement. Il ya aussi quelques arguments dans le pays des tests sur combien vous devriez tester à quel niveau. Ma philosophie personnelle est que vous devriez tester ce que vous voulez réaliser. Dans le cas d'un pipeline de données, il peut s'agir de: extraire un fichier de S3, le traiter et le remettre dans un autre emplacement S3. Parce que j'apprécie le plaisir de jouer en TDD, ce type de test me rend beaucoup plus heureux à mettre en œuvre que des centaines de tests unitaires qui disent la même chose. Un exemple de ce test de traitement de données pourrait être:

pandas d'importation
import moto
from pandas.testing import assert_frame_equal
depuis functions.cake_mixer import mix_ingredients@ pytest.fixture
def Bucket_fixture ():
avec moto.mock_s3 ():
s3_resource = boto3.resource ("s3")
bucket = s3_resource.Bucket ("test")
bucket.create ()
godet à rendement
def test_processing_cake (bucket_fixture):
input_fixture = pandas.read_csv ('fixtures / blend.csv')
output_fixture = pandas.read_csv ('fixtures / cake.csv')
input_fixture.to_parquet ('s3: //test/ingredients/mixture.parquet')
mix_ingredients ({
'seau': 'test_bucket',
'mixture_key': 'ingrédients / mélange.parquet',
'cake_key': 'cake / chocolate.parquet'
})
output = pandas.read_parquet ('s3: //test/cake/chocolate.parquet')
assert_frame_equal (output, output_fixture)

Ce qui fait beaucoup:

  • Met en place des appareils pour S3
  • Télécharge un exemple de fichier test
  • Exécute du code pour traiter l'exemple
  • Lit le fichier résultant
  • Confirme que la sortie attendue correspond à la sortie traitée

Cet exemple illustre les étapes à suivre dans ce type de test. Pour cela, vous pouvez commencer par traiter les données avant même d’impliquer S3:

pandas d'importation
from pandas.testing import assert_frame_equal
depuis functions.cake_mixer import mix_ingredientsdef test_processing_cake ():
input_fixture = pandas.read_csv ('fixtures / blend.csv')
output_fixture = pandas.read_csv ('fixtures / cake.csv')
output = mix_ingredients (input_fixture)
assert_frame_equal (output, output_fixture)

Vous pouvez sentir le code se rassembler lorsque vous écrivez un test en évolution. J'espère que cela résoudra le problème «Je dois changer tous les tests», car vous ne remplissez que les conditions requises. Vous êtes moins vulnérable au changement d’unités étroitement couplées. Un inconvénient est que lorsqu'une unité dispose d'un ensemble complexe d'entrées et de sorties, les tests d'unité peuvent aider à les définir.

Surtout, n’essayez pas d’implémenter trop à la fois, mais visez un résultat plus large. Parfois, vous souhaitez utiliser plusieurs boucles de tests pour vous aider à atteindre un objectif plus large. Pour les pipelines de données, vous pouvez écrire un test pour un pipeline, puis un ensemble de tests plus petits pour chaque étape. Cela signifie que vous pouvez tester les sorties de votre pipeline et une correspondance de pipeline de validation conceptuelle. Pourtant, chaque étape du pipeline comporte des tests pour des transformations spécifiques et explicables. D'une validation de concept de pandas à un pipeline de données à grande échelle, Spark peut utiliser les mêmes données de test de bout en bout.

Les tests sont par nature un jeu amusant, dans lequel vous concevez vos propres défis, puis trouvez le moyen le plus agréable et le plus agréable de les compléter.

Enfin, les gens trouvent de toute façon des tests monotones et je ne peux rien y faire. Les tests sont par nature un jeu amusant, dans lequel vous concevez vos propres défis, puis trouvez le moyen le plus agréable et le plus agréable de les compléter. La meilleure façon de rendre cela plus clair est de trouver vous-même quelqu'un à jumeler et de travailler en utilisant un style de ping-pong. Au ping-pong, une personne écrit un test et l'autre le fait passer. La concurrence pour écrire de meilleurs tests et un meilleur code au fur et à mesure. Le plaisir est de trouver des moyens de faire en sorte que le code fasse des choses inattendues ou de trouver des cas extrêmes qui incitent votre partenaire à penser un peu plus à résoudre. Par exemple, si vous avez une fonction censée renvoyer la valeur transmise, vous pouvez assez facilement écrire ce qui suit:

def test_identity ():
affirmer son identité (1) == 1

Avec lequel vous pouvez très facilement vous amuser, comme indiqué ici:

def identité (x):
retour 1

Cela signifie que votre partenaire doit maintenant implémenter la fonctionnalité attendue. La prochaine fois, l’astuce pourrait consister à vérifier deux valeurs différentes de x pour que vous ne vous amusiez pas trop:

def test_identity ():
affirmer son identité (1) == 1
affirmer l'identité (404) == 404

Vous avez couvert quelques cas supplémentaires et réussi à vous assurer que le code fonctionne exactement comme vous le souhaitiez.

J'espère vraiment que cet article vous montre que, plutôt que d'être un fardeau, TDD vous donne:

  • Compréhension du code que vous êtes sur le point d’écrire et de ce qu’il devrait faire
  • Un filet de sécurité pour continuer à écrire du code épouvantable jusqu'à ce que vous vouliez refactoriser
  • Gamification de votre vie professionnelle, y compris multijoueur!

Donc, même si vous avez déjà essayé, essayez à nouveau TDD, car tout le monde devrait avoir plus de plaisir :-).

Afficher plus

SupportIvy

SupportIvy.com : Un lieu pour partager le savoir et mieux comprendre le monde. Meilleure plate-forme de support gratuit pour vous, Documentation &Tutoriels par les experts.

Articles similaires

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Bouton retour en haut de la page
Fermer