Ce texte est le premier d'une série de textes sur les tests dans les applications de traitement de données que j'apporterai ici et sur mon blog personnel.
Lorsque j'ai fait ma transition de carrière d'ingénieur logiciel à ingénieur de données, j'ai commencé à avoir des conversations avec des personnes dans le domaine des données qui n'avaient pas de formation en génie logiciel. Dans ces conversations, une question revenait à plusieurs reprises : comment rédiger des tests ?
Écrire des tests peut, en effet, paraître une tâche complexe pour ceux qui n'y sont pas habitués, car elle nécessite un changement dans la manière d'écrire du code. La vérité est qu’il n’y a pas de mystère, mais plutôt une question de pratique et de répétition. Mon objectif principal dans cet article est de vous guider, qui débutez, dans un processus qui montre comment nous pouvons créer des tests pour les applications qui traitent des données, garantissant la qualité et la fiabilité du code.
Ce texte fait partie d'une série que j'apporterai au cours des prochaines semaines où je partagerai comment écrire des tests automatisés en code destinés à l'ingénierie des données. Dans l'article d'aujourd'hui, je souhaite explorer un peu les simulations. Dans plusieurs scénarios de code, un pipeline de données établira des connexions, des appels d'API, une intégration avec des services Cloud, etc., ce qui peut créer une certaine confusion sur la façon dont nous pouvons tester cette application. Aujourd'hui, nous allons explorer quelques bibliothèques intéressantes pour écrire des tests axés sur l'utilisation de mocks.
Après tout, que sont les Mocks ?
Les simulacres sont des objets simulés utilisés dans les tests pour imiter le comportement de dépendances ou de composants externes qui ne sont pas au centre du test. Ils vous permettent d'isoler l'unité de code testée, garantissant ainsi que les tests sont plus contrôlables et prédictifs. L'utilisation de simulations est une pratique courante dans les tests unitaires et les tests d'intégration.
Et nous devrions utiliser des simulations quand :
- La dépendance n'est pas pertinente pour le test ;
- La dépendance n'est pas disponible ;
- Nous souhaitons tester des comportements particuliers, des simulations d'erreurs ou des réponses spécifiques.
Dans les pipelines de données, Mocking permet de créer des représentations de composants externes – comme une base de données, un service de messagerie ou une API – sans dépendre de leurs infrastructures réelles. Ceci est particulièrement utile dans les environnements de traitement de données, qui intègrent plusieurs technologies, telles que PySpark pour le traitement distribué, Kafka pour la messagerie, ainsi que des services cloud tels qu'AWS et GCP.
Dans ces scénarios où nous disposons de pipelines de données, Mocking facilite l'exécution de tests isolés et rapides, minimisant les coûts et le temps d'exécution. Il permet de vérifier avec précision chaque partie du pipeline, sans pannes intermittentes causées par des connexions réelles ou une infrastructure externe, et avec la certitude que chaque intégration fonctionne comme prévu.
Dans chaque langage de programmation, on peut trouver des modules internes qui fournissent déjà des fonctions Mock à implémenter. En Python, la bibliothèque native unittest.mock est le principal outil de création de simulations, vous permettant de simuler des objets et des fonctions avec facilité et contrôle. Dans Go, le processus Mocking est généralement pris en charge par des packages externes, tels que Mockery, car le langage ne dispose pas de bibliothèque Mock native ; mockery est particulièrement utile pour générer des mocks à partir d'interfaces, une fonctionnalité native de Go. En Java, Mockito se distingue comme une bibliothèque populaire et puissante pour créer des mocks, s'intégrant à JUnit pour faciliter des tests unitaires robustes. Ces bibliothèques constituent une base essentielle pour tester des composants isolés, en particulier dans les pipelines de données et les systèmes distribués où la simulation de sources de données externes et d'API est essentielle.
Implémentation de simulations
Commençons par un exemple de base de la façon dont nous pouvons utiliser les Mocks. Supposons que nous ayons une fonction qui effectue des appels API et que nous devions écrire des tests unitaires pour cette fonction :
def get_data_from_api(url): import requests response = requests.get(url) if response.status_code == 200: return response.json() else: return None
Pour aborder correctement les scénarios de test, nous devons d'abord comprendre quelles situations doivent être couvertes. Comme notre fonction effectue des appels REST, les tests doivent considérer au moins deux scénarios principaux : un dans lequel la requête réussit et un autre dans lequel la réponse n'est pas celle attendue. Nous pourrions exécuter le code avec une vraie URL pour observer le comportement, mais cette approche présente des inconvénients, car nous n'aurions pas de contrôle sur les différents types de réponses, en plus de laisser le test vulnérable aux changements dans la réponse URL ou à son éventuelle indisponibilité. . Pour éviter ces incohérences, nous utiliserons des Mocks.
from unittest import mock @mock.patch('requests.get') def test_get_data_from_api_success(mock_get): # Configura o mock para retornar uma resposta simulada mock_get.return_value.status_code = 200 mock_get.return_value.json.return_value = {"key": "value"} # Chama a função com o mock ativo result = get_data_from_api("http://fakeurl.com") # Verifica se o mock foi chamado corretamente e o resultado é o esperado mock_get.assert_called_once_with("http://fakeurl.com") self.assertEqual(result, {"key": "value"})
Avec la décoration @mock.patch de la bibliothèque Python unittest, nous pouvons remplacer l'appel request.get par un mock, un "faux objet" qui simule le comportement de la fonction get dans le contexte de test, éliminant la dépendance externe .
En définissant des valeurs pour la return_value du mock, nous pouvons spécifier exactement ce que nous attendons que l'objet renvoie lorsqu'il est appelé dans la fonction que nous testons. Il est important que la structure return_value suive la même chose que les objets réels que nous remplaçons. Par exemple, un objet de réponse du module de requêtes a des attributs comme status_code et des méthodes comme json(). Ainsi, pour simuler une réponse de la fonction request.get, on peut attribuer la valeur attendue à ces attributs et méthodes directement dans le mock.
def get_data_from_api(url): import requests response = requests.get(url) if response.status_code == 200: return response.json() else: return None
Dans ce cas précis, l'objectif est de simuler la réponse à la requête, c'est-à-dire de tester le comportement de la fonction avec différents résultats attendus sans dépendre d'une URL externe et sans impact sur notre environnement de test.
from unittest import mock @mock.patch('requests.get') def test_get_data_from_api_success(mock_get): # Configura o mock para retornar uma resposta simulada mock_get.return_value.status_code = 200 mock_get.return_value.json.return_value = {"key": "value"} # Chama a função com o mock ativo result = get_data_from_api("http://fakeurl.com") # Verifica se o mock foi chamado corretamente e o resultado é o esperado mock_get.assert_called_once_with("http://fakeurl.com") self.assertEqual(result, {"key": "value"})
En simulant les réponses d'erreur de l'API dans les tests, nous pouvons aller au-delà des bases et vérifier le comportement de l'application par rapport à différents types de codes d'état HTTP tels que 404, 401, 500 et 503. Cela offre une couverture plus large et garantit que l'application traite de manière appropriée à chaque type de panne, je comprends comment ces variations dans l'appel peuvent impacter notre application/traitement des données. Dans les appels de méthode POST, nous pouvons ajouter une couche supplémentaire de validation, vérifiant non seulement le status_code et le fonctionnement de base de l'appel, mais également le schéma de la réponse envoyée et reçue, garantissant que les données renvoyées suivent le format attendu. Cette approche de test plus détaillée permet d'éviter de futurs problèmes en garantissant que l'application est prête à gérer une variété de scénarios d'erreur et que les données reçues sont toujours conformes à ce qui a été conçu.
Implémentation de simulations avec PySpark
Maintenant que nous avons vu un cas simple d'utilisation de Mocks dans du code Python pur, étendons nos cas à un extrait de code qui utilise Pyspark.
Pour tester les fonctions PySpark, en particulier les opérations DataFrame telles que filter, groupBy et join, l'utilisation de simulations est une approche efficace qui élimine le besoin d'exécuter un vrai Spark, réduisant ainsi le temps de test et simplifiant l'environnement de développement. La bibliothèque unittest.mock de Python vous permet de simuler les comportements de ces méthodes, permettant ainsi de vérifier le flux de code et la logique sans dépendre de l'infrastructure Spark.
Voyons, étant donné la fonction suivante, où nous avons une transformation qui effectue des opérations de filtrage, groupBy et de jointure sur les dataframes dans Spark.
def get_data_from_api(url): import requests response = requests.get(url) if response.status_code == 200: return response.json() else: return None
Pour exécuter un test PySpark, nous avons besoin que la configuration de Spark soit effectuée localement. Cette configuration se fait dans la méthode setUpClass, qui crée une instance de Spark qui sera utilisée dans tous les tests de la classe. Cela nous permet d'exécuter PySpark de manière isolée, ce qui permet d'effectuer de véritables opérations de transformation sans recourir à un cluster complet. Une fois le test terminé, la méthode tearDownClass est chargée de mettre fin à la session Spark, en garantissant que toutes les ressources sont correctement libérées et que l'environnement de test est propre.
from unittest import mock @mock.patch('requests.get') def test_get_data_from_api_success(mock_get): # Configura o mock para retornar uma resposta simulada mock_get.return_value.status_code = 200 mock_get.return_value.json.return_value = {"key": "value"} # Chama a função com o mock ativo result = get_data_from_api("http://fakeurl.com") # Verifica se o mock foi chamado corretamente e o resultado é o esperado mock_get.assert_called_once_with("http://fakeurl.com") self.assertEqual(result, {"key": "value"})
Dans le test test_transform_data, nous commençons par créer des exemples de DataFrames pour df et df_other, qui contiennent les données qui seront utilisées dans les transformations. Nous exécutons ensuite la fonction transform_data sans appliquer de simulations, permettant aux opérations de filtrage, groupBy et de jointure de se produire réellement et d'aboutir à un nouveau DataFrame. Après exécution, nous utilisons la méthode collect() pour extraire les données du DataFrame résultant, ce qui nous permet de comparer ces données avec les valeurs attendues et, ainsi, de valider la transformation effectuée de manière réelle et précise.
Mais nous pouvons aussi avoir des scénarios dans lesquels nous souhaitons tester le résultat d'une de ces fonctions pyspark. Il est nécessaire de moquer une autre partie du code qui peut représenter un goulot d'étranglement au moment de l'exécution et qui ne représente pas de risque pour notre processus. On peut donc utiliser la technique de moquerie d'une fonction/module, comme nous l'avons vu dans l'exemple précédent en utilisant des requêtes.
response.status_code = mock_get.return_value.status_code response.json() = mock_get.return_value.json.return_value
Le test Mock pour une opération spécifique a été effectué dans la méthode test_transform_data_with_mocked_join, où nous avons appliqué une simulation spécifiquement pour la méthode de filtrage. Cette simulation remplace le résultat de l'opération de jointure par un DataFrame simulé, permettant aux opérations précédentes, telles que groupBy et join, d'être exécutées de manière réelle. Le test compare ensuite le DataFrame résultant avec la valeur attendue, garantissant que la simulation de jointure a été utilisée correctement, sans interférer avec les autres transformations effectuées.
Cette approche hybride apporte plusieurs avantages. En garantissant que les opérations PySpark réelles telles que join et groupBy sont maintenues, nous pouvons valider la logique des transformations sans perdre la flexibilité de remplacer des opérations spécifiques telles que filter par des simulations. Cela se traduit par des tests plus robustes et plus rapides, éliminant le besoin d'un cluster Spark complet, ce qui facilite le développement et la validation continus du code.
Il est important de souligner que cette stratégie doit être utilisée avec prudence et uniquement dans des scénarios où aucun biais dans les résultats n'est créé. Le but du test est de garantir que le traitement se déroule correctement ; Nous ne devrions pas simplement attribuer des valeurs sans réellement tester la fonction. Bien qu'il soit valable de simuler des sections dont nous pouvons garantir qu'elles n'affecteront pas le processus de tests unitaires, il est essentiel de se rappeler que la fonction doit être exécutée pour valider son comportement réel.
Ainsi, l’approche hybride prend beaucoup plus de sens lorsque l’on ajoute d’autres types de traitements à cette fonction. Cette stratégie permet une combinaison efficace d'opérations réelles et simulées, garantissant des tests plus robustes et fiables
Final
Les simulations sont de précieux alliés pour créer des tests efficaces, notamment lorsqu'il s'agit de travailler avec PySpark et d'autres services cloud. L'implémentation que nous avons explorée à l'aide de unittest en Python nous a non seulement aidé à simuler des opérations, mais également à maintenir l'intégrité de nos données et de nos processus. Grâce à la flexibilité offerte par les simulations, nous pouvons tester nos pipelines sans craindre de faire des ravages dans les environnements de production. Alors, prêt pour le prochain défi ? Dans notre prochain texte, nous plongerons dans le monde des intégrations avec les services AWS et GCP, montrant comment simuler ces appels et garantir que vos pipelines fonctionnent parfaitement. À la prochaine fois !
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Pour maximiser l'efficacité de l'apprentissage de Python dans un temps limité, vous pouvez utiliser les modules DateTime, Time et Schedule de Python. 1. Le module DateTime est utilisé pour enregistrer et planifier le temps d'apprentissage. 2. Le module de temps aide à définir l'étude et le temps de repos. 3. Le module de planification organise automatiquement des tâches d'apprentissage hebdomadaires.

Python excelle dans les jeux et le développement de l'interface graphique. 1) Le développement de jeux utilise Pygame, fournissant des fonctions de dessin, audio et d'autres fonctions, qui conviennent à la création de jeux 2D. 2) Le développement de l'interface graphique peut choisir Tkinter ou Pyqt. Tkinter est simple et facile à utiliser, PYQT a des fonctions riches et convient au développement professionnel.

Python convient à la science des données, au développement Web et aux tâches d'automatisation, tandis que C convient à la programmation système, au développement de jeux et aux systèmes intégrés. Python est connu pour sa simplicité et son écosystème puissant, tandis que C est connu pour ses capacités de contrôle élevées et sous-jacentes.

Vous pouvez apprendre les concepts de programmation de base et les compétences de Python dans les 2 heures. 1. Apprenez les variables et les types de données, 2. Flux de contrôle maître (instructions et boucles conditionnelles), 3. Comprenez la définition et l'utilisation des fonctions, 4. Démarrez rapidement avec la programmation Python via des exemples simples et des extraits de code.

Python est largement utilisé dans les domaines du développement Web, de la science des données, de l'apprentissage automatique, de l'automatisation et des scripts. 1) Dans le développement Web, les cadres Django et Flask simplifient le processus de développement. 2) Dans les domaines de la science des données et de l'apprentissage automatique, les bibliothèques Numpy, Pandas, Scikit-Learn et Tensorflow fournissent un fort soutien. 3) En termes d'automatisation et de script, Python convient aux tâches telles que les tests automatisés et la gestion du système.

Vous pouvez apprendre les bases de Python dans les deux heures. 1. Apprenez les variables et les types de données, 2. Structures de contrôle maître telles que si les instructions et les boucles, 3. Comprenez la définition et l'utilisation des fonctions. Ceux-ci vous aideront à commencer à écrire des programmes Python simples.

Comment enseigner les bases de la programmation novice en informatique dans les 10 heures? Si vous n'avez que 10 heures pour enseigner à l'informatique novice des connaissances en programmation, que choisissez-vous d'enseigner ...

Comment éviter d'être détecté lors de l'utilisation de FiddlereVerywhere pour les lectures d'homme dans le milieu lorsque vous utilisez FiddlereVerywhere ...


Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Navigateur d'examen sécurisé
Safe Exam Browser est un environnement de navigation sécurisé permettant de passer des examens en ligne en toute sécurité. Ce logiciel transforme n'importe quel ordinateur en poste de travail sécurisé. Il contrôle l'accès à n'importe quel utilitaire et empêche les étudiants d'utiliser des ressources non autorisées.

MantisBT
Mantis est un outil Web de suivi des défauts facile à déployer, conçu pour faciliter le suivi des défauts des produits. Cela nécessite PHP, MySQL et un serveur Web. Découvrez nos services de démonstration et d'hébergement.

Listes Sec
SecLists est le compagnon ultime du testeur de sécurité. Il s'agit d'une collection de différents types de listes fréquemment utilisées lors des évaluations de sécurité, le tout en un seul endroit. SecLists contribue à rendre les tests de sécurité plus efficaces et productifs en fournissant facilement toutes les listes dont un testeur de sécurité pourrait avoir besoin. Les types de listes incluent les noms d'utilisateur, les mots de passe, les URL, les charges utiles floues, les modèles de données sensibles, les shells Web, etc. Le testeur peut simplement extraire ce référentiel sur une nouvelle machine de test et il aura accès à tous les types de listes dont il a besoin.

ZendStudio 13.5.1 Mac
Puissant environnement de développement intégré PHP