Fabrication industrielle
Internet des objets industriel | Matériaux industriels | Entretien et réparation d'équipement | Programmation industrielle |
home  MfgRobots >> Fabrication industrielle >  >> Industrial programming >> Python

Tutoriel PyTest :qu'est-ce que c'est, comment installer, framework, assertions

Qu'est-ce que PyTest ?

PyTest est un framework de test qui permet aux utilisateurs d'écrire des codes de test à l'aide du langage de programmation Python. Il vous aide à écrire des cas de test simples et évolutifs pour les bases de données, les API ou l'interface utilisateur. PyTest est principalement utilisé pour écrire des tests pour les API. Il aide à écrire des tests allant des tests unitaires simples aux tests fonctionnels complexes.

Pourquoi utiliser PyTest ?

Certains des avantages de pytest sont

Dans ce tutoriel Python PyTest, vous apprendrez :

Comment installer PyTest

Voici un processus d'installation de PyTest :

Étape 1) Vous pouvez installer pytest en

pip install pytest==2.9.1

Une fois l'installation terminée, vous pouvez la confirmer avec par

py.test -h

Cela affichera l'aide

Premier PyTest de base

Maintenant, nous allons apprendre à utiliser Pytest avec un exemple de base de PyTest.

Créez un dossier study_pytest. Nous allons créer nos fichiers de test dans ce dossier.

Veuillez accéder à ce dossier dans votre ligne de commande.

Créez un fichier nommé test_sample1.py dans le dossier

Ajoutez-y le code ci-dessous et enregistrez

import pytest
def test_file1_method1():
	x=5
	y=6
	assert x+1 == y,"test failed"
	assert x == y,"test failed"
def test_file1_method2():
	x=5
	y=6
	assert x+1 == y,"test failed" 

Exécutez le test à l'aide de la commande

py.test

Vous obtiendrez une sortie comme

test_sample1.py F.
============================================== FAILURES ========================================
____________________________________________ test_sample1 ______________________________________
    def test_file1_method1():
    	x=5
    	y=6
       	assert x+1 == y,"test failed"
>      	assert x == y,"test failed"
E       AssertionError: test failed
E       assert 5 == 6
test_sample1.py:6: AssertionError

Ici dans test_sample1.py F.

F dit échec

Le point (.) indique le succès.

Dans la section des échecs, vous pouvez voir la ou les méthodes ayant échoué et la ligne d'échec. Ici x==y signifie 5==6 ce qui est faux.

Ensuite, dans ce didacticiel PyTest, nous en apprendrons davantage sur l'assertion dans PyTest.

Assertions dans PyTest

Les assertions pytest sont des vérifications qui renvoient l'état True ou False. Dans Python Pytest, si une assertion échoue dans une méthode de test, l'exécution de cette méthode est arrêtée là. Le code restant dans cette méthode de test n'est pas exécuté et les assertions Pytest continueront avec la méthode de test suivante.

Exemples d'assertions Pytest :

assert "hello" == "Hai" is an assertion failure.
assert 4==4 is a successful assertion
assert True is a successful assertion
assert False is an assertion failure.

Considérez

assert x == y,"test failed because x=" + str(x) + " y=" + str(y)

Placez ce code dans test_file1_method1() au lieu de l'assertion

assert x == y,"test failed"

L'exécution du test donnera l'échec sous la forme AssertionError :le test a échoué x=5 y=6

Comment PyTest identifie les fichiers de test et les méthodes de test

Par défaut, pytest identifie uniquement les noms de fichiers commençant par test_ ou se terminant par _test que les fichiers de test. Nous pouvons cependant mentionner explicitement d'autres noms de fichiers (expliqués plus tard). Pytest exige que les noms des méthodes de test commencent par "test .” Tous les autres noms de méthodes seront ignorés même si nous demandons explicitement d'exécuter ces méthodes.

Voir quelques exemples de noms de fichiers pytest valides et invalides

test_login.py - valid
login_test.py - valid
testlogin.py -invalid
logintest.py -invalid

Remarque :Oui, nous pouvons explicitement demander à pytest de choisir testlogin.py et logintest.py

Voir quelques exemples de méthodes de test pytest valides et non valides

def test_file1_method1(): - valid
def testfile1_method1(): - valid
def file1_method1(): - invalid	

Remarque :même si nous mentionnons explicitement file1_method1(), pytest n'exécutera pas cette méthode.

Exécuter plusieurs tests à partir d'un fichier spécifique et de plusieurs fichiers

Actuellement, dans le dossier study_pytest, nous avons un fichier test_sample1.py. Supposons que nous ayons plusieurs fichiers, disons test_sample2.py , test_sample3.py. Pour exécuter tous les tests à partir de tous les fichiers du dossier et des sous-dossiers, nous devons simplement exécuter la commande pytest.

py.test

Cela exécutera tous les noms de fichiers commençant par test_ et les noms de fichiers se terminant par _test dans ce dossier et les sous-dossiers de ce dossier.

Pour exécuter des tests uniquement à partir d'un fichier spécifique, nous pouvons utiliser py.test

py.test test_sample1.py

Exécuter un sous-ensemble du test complet avec PyTest

Parfois, nous ne voulons pas exécuter toute la suite de tests. Pytest nous permet d'exécuter des tests spécifiques. Nous pouvons le faire de 2 manières

Nous avons déjà test_sample1.py. Créez un fichier test_sample2.py et ajoutez-y le code ci-dessous

def test_file2_method1():
	x=5
	y=6
	assert x+1 == y,"test failed"
	assert x == y,"test failed because x=" + str(x) + " y=" + str(y)
def test_file2_method2():
	x=5
	y=6
	assert x+1 == y,"test failed"

Nous avons donc actuellement

  • test_sample1.py
    • test_file1_method1()
    • test_file1_method2()
  • test_sample2.py
    • test_file2_method1()
    • test_file2_method2()

Option 1) Exécuter des tests par correspondance de sous-chaîne

Ici, pour exécuter tous les tests ayant method1 dans son nom, nous devons exécuter

py.test -k method1 -v
-k <expression> is used to represent the substring to match
-v increases the verbosity

Donc, exécuter py.test -k method1 -v vous donnera le résultat suivant

test_sample2.py::test_file2_method1 FAILED
test_sample1.py::test_file1_method1 FAILED

============================================== FAILURES ==============================================
_________________________________________ test_file2_method1 _________________________________________
    def test_file2_method1():
    	x=5
    	y=6
       	assert x+1 == y,"test failed"
>      	assert x == y,"test failed because x=" + str(x) + " y=" + str(y)
E       AssertionError: test failed because x=5 y=6
E       assert 5 == 6
test_sample2.py:5: AssertionError

_________________________________________ test_file1_method1 _________________________________________
    @pytest.mark.only
    def test_file1_method1():
    	x=5
    	y=6
       	assert x+1 == y,"test failed"
>      	assert x == y,"test failed because x=" + str(x) + " y=" + str(y)
E       AssertionError: test failed because x=5 y=6
E       assert 5 == 6
test_sample1.py:8: AssertionError

================================= 2 tests deselected by '-kmethod1' ==================================
=============================== 2 failed, 2 deselected in 0.02 seconds ===============================

Ici vous pouvez voir vers la fin 2 tests désélectionnés par '-kmethod1' qui sont test_file1_method2 et test_file2_method2

Essayez de courir avec différentes combinaisons comme :-

py.test -k method -v - will run all the four methods
py.test -k methods -v – will not run any test as there is no test name matches the substring 'methods'

Option 2) Exécuter des tests par des marqueurs

Pytest nous permet de définir divers attributs pour les méthodes de test à l'aide de marqueurs pytest, @pytest.mark . Pour utiliser des marqueurs dans le fichier de test, nous devons importer pytest sur les fichiers de test.

Ici, nous appliquerons différents noms de marqueurs pour tester les méthodes et exécuterons des tests spécifiques basés sur les noms de marqueurs. Nous pouvons définir les marqueurs sur chaque nom de test en utilisant

@pytest.mark.<name>.			

Nous définissons les marqueurs set1 et set2 sur les méthodes de test, et nous exécuterons le test en utilisant les noms des marqueurs. Mettez à jour les fichiers de test avec le code suivant

test_sample1.py

import pytest
@pytest.mark.set1
def test_file1_method1():
	x=5
	y=6
	assert x+1 == y,"test failed"
	assert x == y,"test failed because x=" + str(x) + " y=" + str(y)

@pytest.mark.set2
def test_file1_method2():
	x=5
	y=6
	assert x+1 == y,"test failed"

test_sample2.py

import pytest
@pytest.mark.set1
def test_file2_method1():
	x=5
	y=6
	assert x+1 == y,"test failed"
	assert x == y,"test failed because x=" + str(x) + " y=" + str(y)

@pytest.mark.set1
def test_file2_method2():
	x=5
	y=6
	assert x+1 == y,"test failed"

Nous pouvons exécuter le test marqué par

py.test -m <name>
-m <name> mentions the marker name

Exécutez py.test -m set1. Cela exécutera les méthodes test_file1_method1, test_file2_method1, test_file2_method2.

L'exécution de py.test -m set2 exécutera test_file1_method2.

Exécuter des tests en parallèle avec Pytest

Habituellement, une suite de tests aura plusieurs fichiers de test et des centaines de méthodes de test dont l'exécution prendra un temps considérable. Pytest nous permet d'exécuter des tests en parallèle.

Pour cela, nous devons d'abord installer pytest-xdist en exécutant

pip install pytest-xdist

Vous pouvez exécuter des tests maintenant en

py.test -n 4

-n exécute les tests en utilisant plusieurs nœuds de calcul. Dans la commande ci-dessus, il y aura 4 travailleurs pour exécuter le test.

Appareils Pytest

Les appareils sont utilisés lorsque nous voulons exécuter du code avant chaque méthode de test. Ainsi, au lieu de répéter le même code à chaque test, nous définissons des appareils. Habituellement, les appareils sont utilisés pour initialiser les connexions à la base de données, passer la base , etc

Une méthode est marquée comme un luminaire Pytest en marquant avec

@pytest.fixture

Une méthode de test peut utiliser un luminaire Pytest en mentionnant le luminaire comme paramètre d'entrée.

Créez un nouveau fichier test_basic_fixture.py avec le code suivant

import pytest
@pytest.fixture
def supply_AA_BB_CC():
	aa=25
	bb =35
	cc=45
	return [aa,bb,cc]

def test_comparewithAA(supply_AA_BB_CC):
	zz=35
	assert supply_AA_BB_CC[0]==zz,"aa and zz comparison failed"

def test_comparewithBB(supply_AA_BB_CC):
	zz=35
	assert supply_AA_BB_CC[1]==zz,"bb and zz comparison failed"

def test_comparewithCC(supply_AA_BB_CC):
	zz=35
	assert supply_AA_BB_CC[2]==zz,"cc and zz comparison failed"

Ici

Chacune des fonctions de test a un argument d'entrée dont le nom correspond à un appareil disponible. Pytest invoque alors la méthode de fixation correspondante et les valeurs renvoyées seront stockées dans l'argument d'entrée , ici la liste [25,35,45]. Désormais, les éléments de la liste sont utilisés dans les méthodes de test pour la comparaison.

Lancez maintenant le test et voyez le résultat

 py.test test_basic_fixture
test_basic_fixture.py::test_comparewithAA FAILED                                                                                                                                                                                       
test_basic_fixture.py::test_comparewithBB PASSED                                                                                                                                                                                       
test_basic_fixture.py::test_comparewithCC FAILED
                                                                                                                                                                                       
============================================== FAILURES ==============================================
_________________________________________ test_comparewithAA _________________________________________
supply_AA_BB_CC = [25, 35, 45]
    def test_comparewithAA(supply_AA_BB_CC):
    	zz=35
>   	assert supply_AA_BB_CC[0]==zz,"aa and zz comparison failed"
E    AssertionError: aa and zz comparison failed
E    assert 25 == 35
test_basic_fixture.py:10: AssertionError

_________________________________________ test_comparewithCC _________________________________________
supply_AA_BB_CC = [25, 35, 45]
    def test_comparewithCC(supply_AA_BB_CC):
    	zz=35
>   	assert supply_AA_BB_CC[2]==zz,"cc and zz comparison failed"
E    AssertionError: cc and zz comparison failed
E    assert 45 == 35
test_basic_fixture.py:16: AssertionError
================================= 2 failed, 1 passed in 0.05 seconds =================================

Le test test_comparewithBB est réussi puisque zz=BB=35, et les 2 tests restants échouent.

La méthode de fixation a une portée uniquement dans le fichier de test où elle est définie. Si nous essayons d'accéder à l'appareil dans un autre fichier de test, nous obtiendrons une erreur indiquant que l'appareil 'supply_AA_BB_CC' not found pour les méthodes de test dans d'autres fichiers.

Pour utiliser le même appareil sur plusieurs fichiers de test, nous allons créer des méthodes d'appareil dans un fichier appelé conftest.py.

Voyons cela par l'exemple PyTest ci-dessous. Créez 3 fichiers conftest.py, test_basic_fixture.py, test_basic_fixture2.py avec le code suivant

conftest.py

import pytest
@pytest.fixture
def supply_AA_BB_CC():
	aa=25
	bb =35
	cc=45
	return [aa,bb,cc]

test_basic_fixture.py

import pytest
def test_comparewithAA(supply_AA_BB_CC):
	zz=35
	assert supply_AA_BB_CC[0]==zz,"aa and zz comparison failed"

def test_comparewithBB(supply_AA_BB_CC):
	zz=35
	assert supply_AA_BB_CC[1]==zz,"bb and zz comparison failed"

def test_comparewithCC(supply_AA_BB_CC):
	zz=35
	assert supply_AA_BB_CC[2]==zz,"cc and zz comparison failed"

test_basic_fixture2.py

import pytest
def test_comparewithAA_file2(supply_AA_BB_CC):
	zz=25
	assert supply_AA_BB_CC[0]==zz,"aa and zz comparison failed"

def test_comparewithBB_file2(supply_AA_BB_CC):
	zz=25
	assert supply_AA_BB_CC[1]==zz,"bb and zz comparison failed"

def test_comparewithCC_file2(supply_AA_BB_CC):
	zz=25
	assert supply_AA_BB_CC[2]==zz,"cc and zz comparison failed"

pytest recherchera d'abord l'appareil dans le fichier de test et s'il n'est pas trouvé, il cherchera dans conftest.py

Exécutez le test par py.test -k test_comparewith -v pour obtenir le résultat ci-dessous

test_basic_fixture.py::test_comparewithAA FAILED  
test_basic_fixture.py::test_comparewithBB PASSED 
test_basic_fixture.py::test_comparewithCC FAILED 
test_basic_fixture2.py::test_comparewithAA_file2 PASSED 
test_basic_fixture2.py::test_comparewithBB_file2 FAILED 
test_basic_fixture2.py::test_comparewithCC_file2 FAILED

Test paramétré Pytest

Le but du paramétrage d'un test est d'exécuter un test sur plusieurs ensembles d'arguments. Nous pouvons le faire par @pytest.mark.parametrize.

Nous verrons cela avec l'exemple PyTest ci-dessous. Ici, nous allons passer 3 arguments à une méthode de test. Cette méthode de test ajoutera les 2 premiers arguments et les comparera avec le 3ème argument.

Créez le fichier de test test_addition.py avec le code ci-dessous

import pytest
@pytest.mark.parametrize("input1, input2, output",[(5,5,10),(3,5,12)])
def test_add(input1, input2, output):
	assert input1+input2 == output,"failed"

Ici, la méthode de test accepte 3 arguments - input1, input2, output. Il ajoute input1 et input2 et compare avec la sortie.

Exécutons le test par py.test -k test_add -v et voyons le résultat

test_addition.py::test_add[5-5-10] PASSED                                                                                                                                                                                              
test_addition.py::test_add[3-5-12] FAILED                                                                                                                                                                                              
============================================== FAILURES ==============================================
__________________________________________ test_add[3-5-12] __________________________________________
input1 = 3, input2 = 5, output = 12
    @pytest.mark.parametrize("input1, input2, output",[(5,5,10),(3,5,12)])
    def test_add(input1, input2, output):
>   	assert input1+input2 == output,"failed"
E    AssertionError: failed
E    assert (3 + 5) == 12
test_addition.py:5: AssertionError

Vous pouvez voir les tests exécutés 2 fois - l'un vérifiant 5+5 ==10 et l'autre vérifiant 3+5 ==12

test_addition.py::test_add[5-5-10] RÉUSSI

test_addition.py::test_add[3-5-12] ÉCHEC

Pytest Xfail/Ignorer les tests

Il y aura des situations où nous ne voulons pas exécuter un test, ou un cas de test n'est pas pertinent à un moment donné. Dans ces situations, nous avons la possibilité de Xéchouer au test ou de sauter les tests

Le test xfailed sera exécuté, mais il ne sera pas compté comme une partie des tests échoués ou réussis. Aucune trace ne sera affichée si ce test échoue. Nous pouvons échouer les tests en utilisant

@pytest.mark.xfail.

Ignorer un test signifie que le test ne sera pas exécuté. Nous pouvons ignorer les tests en utilisant

@pytest.mark.skip.

Modifiez le test_addition.py avec le code ci-dessous

import pytest
@pytest.mark.skip
def test_add_1():
	assert 100+200 == 400,"failed"

@pytest.mark.skip
def test_add_2():
	assert 100+200 == 300,"failed"

@pytest.mark.xfail
def test_add_3():
	assert 15+13 == 28,"failed"

@pytest.mark.xfail
def test_add_4():
	assert 15+13 == 100,"failed"

def test_add_5():
	assert 3+2 == 5,"failed"

def test_add_6():
	assert 3+2 == 6,"failed"

Ici

Exécutez le test par py.test test_addition.py -v et voyez le résultat

test_addition.py::test_add_1 SKIPPED
test_addition.py::test_add_2 SKIPPED
test_addition.py::test_add_3 XPASS
test_addition.py::test_add_4 xfail
test_addition.py::test_add_5 PASSED
test_addition.py::test_add_6 FAILED

============================================== FAILURES ==============================================
_____________________________________________ test_add_6 _____________________________________________
    def test_add_6():
>   	assert 3+2 == 6,"failed"
E    AssertionError: failed
E    assert (3 + 2) == 6
test_addition.py:24: AssertionError

================ 1 failed, 1 passed, 2 skipped, 1 xfailed, 1 xpassed in 0.07 seconds =================

XML des résultats

Nous pouvons créer des résultats de test au format XML que nous pouvons transmettre aux serveurs d'intégration continue pour un traitement ultérieur, etc. Cela peut être fait par

py.test test_sample1.py -v –junitxml=”result.xml”

Le result.xml enregistrera le résultat de l'exécution du test. Trouvez un exemple de result.xml ci-dessous

<?xml version="1.0" encoding="UTF-8"?>
<testsuite errors="0" failures="1" name="pytest" skips="0" tests="2" time="0.046">
   <testcase classname="test_sample1" file="test_sample1.py" line="3" name="test_file1_method1" time="0.001384973526">
     <failure message="AssertionError:test failed because x=5 y=6 assert 5 ==6">
    @pytest.mark.set1
    def test_file1_method1():
    	x=5
    	y=6
       	assert x+1 == y,"test failed"
>      	assert x == y,"test failed because x=" + str(x) + " y=" + str(y)
E       AssertionError: test failed because x=5 y=6
E       assert 5 == 6
         test_sample1.py:9: AssertionError
    </failure>
   </testcase>
   <testcase classname="test_sample1" file="test_sample1.py" line="10" name="test_file1_method2" time="0.000830173492432" />
</testsuite>

De nous pouvons voir un total de deux tests dont un a échoué. Ci-dessous, vous pouvez voir les détails concernant chaque test exécuté sous la balise .

Framework Pytest pour tester une API

Nous allons maintenant créer un petit framework pytest pour tester une API. L'API utilisée ici est une API gratuite de https://reqres.in/. Ce site Web est juste pour fournir une API testable. Ce site Web ne stocke pas nos données.

Ici, nous allons écrire quelques tests pour

Créez les fichiers ci-dessous avec le code donné

conftest.py - avoir un appareil qui fournira l'URL de base pour toutes les méthodes de test

import pytest
@pytest.fixture
def supply_url():
	return "https://reqres.in/api"

test_list_user.py - contient les méthodes de test pour répertorier les utilisateurs valides et non valides

import pytest
import requests
import json
@pytest.mark.parametrize("userid, firstname",[(1,"George"),(2,"Janet")])
def test_list_valid_user(supply_url,userid,firstname):
	url = supply_url + "/users/" + str(userid)
	resp = requests.get(url)
	j = json.loads(resp.text)
	assert resp.status_code == 200, resp.text
	assert j['data']['id'] == userid, resp.text
	assert j['data']['first_name'] == firstname, resp.text

def test_list_invaliduser(supply_url):
	url = supply_url + "/users/50"
	resp = requests.get(url)
	assert resp.status_code == 404, resp.text

test_login_user.py - contient des méthodes de test pour tester la fonctionnalité de connexion.

import pytest
import requests
import json
def test_login_valid(supply_url):
	url = supply_url + "/login/" 
	data = {'email':'[email protected]','password':'something'}
	resp = requests.post(url, data=data)
	j = json.loads(resp.text)
	assert resp.status_code == 200, resp.text
	assert j['token'] == "QpwL5tke4Pnpja7X", resp.text

def test_login_no_password(supply_url):
	url = supply_url + "/login/" 
	data = {'email':'[email protected]'}
	resp = requests.post(url, data=data)
	j = json.loads(resp.text)
	assert resp.status_code == 400, resp.text
	assert j['error'] == "Missing password", resp.text

def test_login_no_email(supply_url):
	url = supply_url + "/login/" 
	data = {}
	resp = requests.post(url, data=data)
	j = json.loads(resp.text)
	assert resp.status_code == 400, resp.text
	assert j['error'] == "Missing email or username", resp.text

Exécutez le test en utilisant py.test -v

Voir le résultat comme

test_list_user.py::test_list_valid_user[1-George] PASSED                                                                                                                                                                               
test_list_user.py::test_list_valid_user[2-Janet] PASSED                                                                                                                                                                                
test_list_user.py::test_list_invaliduser PASSED                                                                                                                                                                                        
test_login_user.py::test_login_valid PASSED                                                                                                                                                                                            
test_login_user.py::test_login_no_password PASSED                                                                                                                                                                                      
test_login_user.py::test_login_no_email PASSED

Mettez à jour les tests et essayez différentes sorties

Résumé

Dans ce tutoriel PyTest, nous avons couvert


Python

  1. Comment installer WordPress sur Google Cloud
  2. Tutoriel sur le cadre d'automatisation des tests codés de l'interface utilisateur
  3. Qu'est-ce qu'une clé de sécurité réseau ? Comment le trouver ?
  4. Qu'est-ce que les appels Wi-Fi ? Comment ça marche ?
  5. Qu'est-ce que la 6G et quelle sera sa vitesse ?
  6. Comment installer un niveleur de quai
  7. Test de décharge partielle :qu'est-ce que c'est et comment ça marche
  8. Qu'est-ce que la cavitation de la pompe et comment l'éviter ?
  9. Qu'est-ce que le brasage au cuivre et comment le faire ?