Une traduction de l'article a été préparée spécialement pour les étudiants du cours Python QA Engineer .
Nous vivons à une époque où les logiciels évoluent très rapidement sur le marché. Pour cette raison, le processus de développement devient très stressant. Des taux élevés d'implémentation de logiciels et de livraison rapide semblent être une bonne partie du modèle d'entreprise, mais la question se pose ici de savoir comment fournir des logiciels de bonne qualité.
Pourquoi avons-nous besoin de tests automatisés
Les tests automatisés présentent de nombreux avantages, en voici trois principaux:
Réutilisation: il n'est pas nécessaire d'écrire de nouveaux scripts à chaque fois, même lors de la publication d'une nouvelle version du système d'exploitation, sauf en cas de besoin urgent.
Fiabilité: les gens ont tendance à faire des erreurs et les voitures les rendent moins probables. Et ils fonctionnent plus rapidement lors de l'exécution d'étapes / tests répétés qui doivent être effectués en continu.
Travail 24h / 24 et 7j / 7: vous pouvez commencer les tests à tout moment de la journée, même à distance. Si vous commencez le test la nuit, il s'exécutera même pendant votre sommeil.
Développement d'un outil de test Pytest complet en Python
Actuellement, il existe de nombreux cadres et outils pour les tests. Il existe différents types de frameworks, par exemple, pilotés par les données, pilotés par mots clés, hybrides, BDD, etc. Vous pouvez choisir celui qui correspond le mieux à vos besoins.
Je dois dire que Python et
pytest
occupent une énorme niche dans ce domaine. Python et ses outils associés sont largement utilisés, probablement parce qu'ils sont plus accessibles aux personnes ayant peu d'expérience en programmation par rapport aux autres langages.
Le cadre
pytest
facilite l'écriture de petits tests, mais il évolue également pour prendre en charge les tests fonctionnels sophistiqués des applications et des bibliothèques.
Quelques caractéristiques clés de
pytest
:
- Détection automatique des modules et fonctions de test;
- CLI efficace pour améliorer le contrôle sur ce que vous souhaitez exécuter ou ignorer;
- Large écosystème tiers de plugins;
- Fixtures - différents types, différentes applications;
- Travailler avec le cadre traditionnel de tests unitaires.
Détection de test automatique et configurable
Par défaut,
pytest
s'attend à trouver des tests dans les modules Python dont les noms commencent par
test_
ou se terminent par
_test.py
. De plus, par défaut, il s'attend à ce que les noms des fonctions de test commencent par le préfixe
test_
. Cependant, ce protocole de détection de test peut être modifié en ajoutant votre propre configuration à l'un des
pytest
configuration
pytest
.
Regardons une fonction de test très simple:
class CheckClass(object): def one_check(self): x = "this" assert 'h' in x def two_check(self): x = "hello" assert hasattr(x, 'check')
Avez-vous remarqué quelque chose? Il n'y a pas d'
assertEqual
ou
assertDictEqual
, juste une
assertDictEqual
accessible et compréhensible. Il n'est pas nécessaire d'importer ces fonctions pour comparer simplement deux objets. Assert est ce que Python a déjà et il n'est pas nécessaire de réinventer la roue.
Code de modèle? Ne vous inquiétez pas, les luminaires se précipitent à la rescousse!
Regardez les fonctions de test qui testent les opérations de base dans le programme Wallet:
// test_wallet.py from wallet import Wallet def test_default_initial_amount(): wallet = Wallet() assert wallet.balance == 0 wallet.close() def test_setting_initial_amount(): wallet = Wallet(initial_amount=100) assert wallet.balance == 100 wallet.close() def test_wallet_add_cash(): wallet = Wallet(initial_amount=10) wallet.add_cash(amount=90) assert wallet.balance == 100 wallet.close() def test_wallet_spend_cash(): wallet = Wallet(initial_amount=20) wallet.spend_cash(amount=10) assert wallet.balance == 10 wallet.close()
Ahem, intéressant! Tu as remarqué? Il y a beaucoup de code passe-partout. Une autre chose à noter est que ce test fait autre chose que tester la partie fonctionnelle, par exemple, créer un portefeuille et le fermer avec
wallet.close()
.
Voyons maintenant comment vous pouvez vous débarrasser du code passe-partout en utilisant des
pytest
Pytest.
import pytest from _pytest.fixtures import SubRequest from wallet import Wallet
C'est bien, non? Les fonctions de test sont désormais compactes et font exactement ce qu'elles devraient faire. Le portefeuille est configuré, installé et fermé à l'aide du
wallet
. Les appareils non seulement aident à écrire du code réutilisable, mais ajoutent également le concept de partage de données. Si vous regardez de plus près, la quantité dans le
wallet
fait partie des données de test fournies en externe par la logique de test et n'est pas fixée de manière rigide à l'intérieur de la fonction.
@pytest.mark.parametrize('wallet', [(10,)], indirect=True)
Dans un environnement plus contrôlé, vous pouvez avoir un fichier avec des données de test, par exemple
test-data.ini
dans votre référentiel ou shell, qui peut le lire, tandis que votre fonction de test peut appeler différents shells pour lire les données de test.
Il est cependant recommandé de placer tous vos appareils dans un fichier
conftest.py
spécial. Il s'agit d'un fichier spécial dans pytest qui permet au test de détecter les appareils globaux.
Mais j'ai des cas de test que je veux exécuter sur différents jeux de données!
Ne vous inquiétez pas,
pytest
a une fonctionnalité intéressante pour paramétrer votre appareil. Regardons un exemple.
Supposons que votre produit dispose d'une CLI gérée localement. De plus, votre produit possède de nombreux paramètres par défaut définis au démarrage et vous souhaitez vérifier toutes les valeurs de ces paramètres.
Vous pourriez penser à écrire un cas de test séparé pour chacun de ces paramètres, mais avec
pytest
tout est beaucoup plus simple!
@pytest.mark.parametrize(“setting_name, setting_value”, [('qdb_mem_usage', 'low'), ('report_crashes', 'yes'), ('stop_download_on_hang', 'no'), ('stop_download_on_disconnect', 'no'), ('reduce_connections_on_congestion', 'no'), ('global.max_web_users', '1024'), ('global.max_downloads', '5'), ('use_kernel_congestion_detection', 'no'), ('log_type', 'normal'), ('no_signature_check', 'no'), ('disable_xmlrpc', 'no'), ('disable_ntp', 'yes'), ('ssl_mode', 'tls_1_2'),])def test_settings_defaults(self, setting_name, setting_value): assert product_shell.run_command(setting_name) == \ self.”The current value for \'{0}\' is \'{1}\'.”.format(setting_name, setting_value), \ 'The {} default should be {}'.format(preference_name, preference_value)
Cool, non? Vous venez d'écrire 13 cas de test (chacun définit une valeur de
setting_value
différente), et à l'avenir, si vous ajoutez un nouveau paramètre à votre produit, tout ce que vous devez faire est d'ajouter un autre tuple.
Comment pytest s'intègre-t-il aux tests d'interface utilisateur avec Selenium et aux tests API?
Eh bien, votre produit peut avoir plusieurs interfaces. CLI - comme nous l'avons dit ci-dessus. Similaire à l'interface graphique et à l'API. Avant de déployer votre produit logiciel, il est important de les tester tous. Dans les logiciels d'entreprise, où plusieurs composants sont interconnectés et dépendent les uns des autres, une modification d'une partie peut affecter toutes les autres.
N'oubliez pas que
pytest
n'est qu'un cadre pour des tests faciles, pas un type spécifique de test. Autrement dit, vous pouvez créer des tests pour l'interface graphique à l'aide de Selenium ou, par exemple, des tests pour l'API avec la bibliothèque de
requests
de Python et les exécuter avec
pytest
.
Par exemple, à un niveau élevé, cela peut être une vérification de la structure du référentiel.

Comme vous le voyez dans l'image ci-dessus, cela donne une bonne occasion de séparer les composants:
apiobjects : un bon endroit pour créer des wrappers pour appeler des points de terminaison d'API. Vous pouvez avoir un
BaseAPIObject
et une classe dérivée qui répondent à vos besoins.
helpers : Vous pouvez ajouter vos méthodes d'assistance ici.
lib : fichiers de bibliothèque pouvant être utilisés par divers composants, par exemple, vos
conftest
dans
conftest
,
pageobjects
, etc.
pageobjects : le
modèle d' architecture
PageObjects peut être utilisé pour créer des classes pour diverses pages GUI. Nous utilisons
Webium , qui est une bibliothèque d'implémentations de modèles d'objet de page pour Python.
suites : vous pouvez écrire vos propres ensembles de vérifications de code pour le code, ils vous aideront à gagner plus de confiance dans la qualité de votre code.
tests : vous pouvez cataloguer les tests en fonction de vos préférences. Cela facilitera la gestion et la révision de vos tests.
Je l'ai apporté juste pour référence, la structure du référentiel et les dépendances peuvent être organisées en fonction de vos besoins personnels.
J'ai de nombreux cas de test et je veux qu'ils fonctionnent en parallèle
Vous pouvez avoir de nombreux cas de test dans votre ensemble, et il arrive que vous deviez les exécuter en parallèle et réduire le temps d'exécution global des tests.
Pytest propose un plug-in étonnant pour exécuter des tests en parallèle appelé
pytest-xdist
, qui ajoute plusieurs modes d'exécution uniques au pytest de base. Installez ce plugin à l'aide de
pip
.
pip install pytest-xdist
Voyons comment cela fonctionne avec un exemple.
J'ai un référentiel de tests automatisé CloudApp pour mes tests Selenium GUI. De plus, il est en constante augmentation et mis à jour avec de nouveaux tests et il a maintenant des centaines de tests. Ce que je veux faire, c'est les exécuter en parallèle et réduire le temps d'exécution global des tests.
Dans le terminal, tapez simplement
pytest
dans le dossier racine du projet / dossier de test. Cela vous permettra d'exécuter tous les tests.
pytest -s -v -n=2

pytest-xdist
exécutera tous les tests en parallèle!
De cette façon, vous pouvez également exécuter plusieurs navigateurs en parallèle.
Rapports
Pytest est livré avec un support intégré pour créer des fichiers de résultats de test qui peuvent être ouverts à l'aide de Jenkins, Bamboo ou d'autres serveurs d'intégration continue. Utilisez ce qui suit:
pytest test/file/path — junitxml=path
Cela aidera à générer un excellent fichier XML qui peut être ouvert avec de nombreux analyseurs.
Conclusion
La popularité de Pytest augmente chaque année. En outre, il dispose d'un puissant support communautaire, qui vous permet d'accéder à de nombreuses extensions, telles que
pytest-django , qui vous aideront à écrire des tests pour les applications Web dans Django. N'oubliez pas que pytest prend en charge les cas de test les plus intacts, donc si vous utilisez
unittest
, pytest doit être considéré plus en détail.
Les sources
C’est tout. Rendez-vous sur le
parcours !