Marco de prueba de Pytest (4) --- uso de decoradores

Tabla de contenido

1. Decorador de accesorios

1.1 Introducción y uso del archivo conftest.py de fixture

1.1.1 Introducción

1.1.2 Ejemplo de uso

1.2.3, el alcance de conftest.py

1.2, accesorios múltiples

 1.3 Llamadas mutuas de fixtures

1.4 El alcance del accesorio

1.4.1 Introducción

1.4.2, la diferencia de alcance entre clase y función en el alcance

1.4.3, la diferencia entre el alcance de la sesión y el alcance del módulo

1.5, gestión de casos de uso de accesorios

1.5.1, omitir caso de uso skip/skipif

1.5.2, marcado fallido xfail

1.5.3, repetir ejecución repetir

1.6 Mecanismo de afirmación del fixture

1.6.1, afirmaciones comunes

1.7 Use el decorador pytest.fiture para transportar parámetros

1.7.1 Usar el parámetro params en el objeto de prueba de firmware

1.7.1 Analizar el archivo yaml para transferir datos

1,8, marca marca personalizada

1.8.1, marcar casos de prueba personalizados y ejecutar casos de prueba de acuerdo con las marcas


1. Decorador de accesorios

1.1 Introducción y uso del archivo conftest.py de fixture

1. 1. 1. Introducción _ _

       Archivo conftest.py: Es una cosa muy importante en el marco pytest, que puede darse cuenta de la auto-correspondencia de los objetos fijos y aplicar automáticamente las operaciones de aplicación entre plantillas y archivos cruzados, para que la definición de los objetos fijos sea más flexible. y conveniente;

1 . 1 . 2. Ejemplo de uso

1. Cree un directorio demo7, cree dos directorios (test_case1 y test_case2) y un archivo (congtest.py) en este directorio, cree archivos de prueba (test_1.py y test_2.py) en el directorio test_1 y cree archivos de prueba en test_2 ( prueba_3.py);

2. Contenido del archivo conftest.py:

import pytest

@pytest.fixture()
def get_data():
    a = '-------1-------'
    b = 2
    print(a)
    return b

 3. El contenido del archivo test_1.py: (test_1_1 y test_1_3 se refieren a la función general get_data del archivo conftest.py)

import  pytest
def test_1_1(get_data):
    sun = 1+get_data
    print(sun)
    print('-----test_1_1----')

def test_1_2():
    print('-----test_1_2----')


def test_1_3(get_data):
    sun = 2+get_data
    print(sun)
    print('-----test_1_3----')
if __name__ == '__main__':
    pytest.main()

4. Contenido del archivo test_2.py: (test_2_1 se refiere a la función general get_data del archivo conftest.py)

import  pytest
def test_2_1(get_data):
    sun = 10+get_data
    print(sun)
    print('-----test_2-1----')

def test_2_2():
    print('-----test_2-2----')


def test_2_3():
    print('-----test_2-3----')
if __name__ == '__main__':
    pytest.main()

5. Contenido del archivo test_3.py: (test_3_1 y test_3_3 se refieren a la función general get_data del archivo conftest.py)

import  pytest
def test_3_1(get_data):
    sun = 100+get_data
    print(sun)
    print('-----test_3_1----')

def test_3_2():
    print('-----test_3_2----')


def test_3_3(get_data):
    sun = 200+get_data
    print(sun)
    print('-----test_3_3----')
if __name__ == '__main__':
    pytest.main(['-s', ['test_3.py']])

 6. Ejecute tres archivos de prueba (ejecute todos los archivos de prueba en el directorio demo7)

7. Resultados de la prueba:

A partir de los resultados, se puede ver que se hace referencia a la función get_data en conftest.py en todos los directorios y archivos.

1. 2. 3. Alcance de conftest.py

1. Puede haber varios archivos conftest.py en un proyecto de prueba. Si hay más de uno, el alcance será diferente según la ubicación de conftest.py; en el directorio raíz del proyecto, este archivo desempeñará un papel global. Si está en un subdirectorio, el archivo solo es válido para los objetos del archivo y los subdirectorios del nivel actual;

2. Las siguientes situaciones son las siguientes:

2.1 Agregue o elimine un archivo conftest.py en el directorio test_case1: (el nombre de la función en este archivo es el mismo que el nombre de la función en conftest.py en el directorio raíz del proyecto ( demo 7) )

2.2 Contenido del archivo:

import pytest

@pytest.fixture()
def get_data():
    a = '-------data2-------'
    b = 2
    print(a)
    return b

2.3 Ejecute todos los archivos de prueba bajo demo7 nuevamente, y los resultados de la prueba son los siguientes: ( Los archivos de prueba en test_case1 se refieren a las funciones en conftest.py en su propio directorio )

2.4 Resumen: cuando el nombre de la función en el directorio del proyecto raíz (demo7) conftest.py es el mismo que el nombre de la función en el subdirectorio (test_case1) conftest.py, el archivo de prueba en el directorio test_case1 tiene prioridad para usar conftest. py en su propio directorio, y solo los objetos en el nivel actual y los subdirectorios no se aplican a test_case2, test_case2 usa conftest.py en el directorio demo7 (actúa globalmente);

3.1 Agregue o elimine un archivo conftest.py en el directorio test_case1: (El nombre de la función en este archivo es diferente del nombre de la función en conftest.py en el directorio raíz del proyecto ( demo 7) ) El archivo test_1.py en test_case1 usa dos funciones;

3.2 Modifique test_1.py de la siguiente manera:

import  pytest
def test_1_1(get_data):   # 引用根工程目录(demo7)下的conftest.py的函数
    sun = 1+get_data
    print(sun)
    print('-----test_1_1----')

def test_1_2():
    print('-----test_1_2----')


def test_1_3(get_data2):  # 引用test_case1下的conftest.py的函数
    sun = 2+get_data2
    print(sun)
    print('-----test_1_3----')
if __name__ == '__main__':
    pytest.main()

 3.3 Ejecute el archivo test_1.py, el resultado es el siguiente:

1. 2. Accesorios múltiples

1. El código de muestra del archivo conftest.py es el siguiente:

import pytest

@pytest.fixture()
def get_data1():
    a = '-------100-------'
    b = 20
    print(a)
    return b


@pytest.fixture()
def get_data2():
    a = '-------200-------'
    c = 30
    print(a)
    return c

 2. El archivo de prueba test_4.py es el siguiente:

import  pytest
def test_3_1(get_data1, get_data2):
    sun = get_data1+get_data2
    print(sun)
if __name__ == '__main__':
    pytest.main(['-s', 'test_4.py'])

3. El resultado de ejecutar el archivo test_4.py es el siguiente:

 1.3 Llamadas mutuas de fixtures

1. El código de muestra del archivo conftest.py es el siguiente: (data2 llama a data1)

import pytest

@pytest.fixture()
def data1():
    print('----data1---')
    a = 1
    return a


@pytest.fixture()
def data2(data1):    # 调用data1的数据
    print('----data2---')
    b = 2+data1
    return b

2. El archivo de prueba test_1.py es el siguiente:

import pytest

def test_1(data2):
    sum = 100+data2
    print(sum)
    assert sum==103

if __name__ == '__main__':
    pytest.main()

3. Resultado de la ejecución:

1. 4. El alcance de la luminaria

1. 4. 1. Introducción _ _

1. Hay un alcance de parámetro en el accesorio, que puede controlar el alcance del objeto de accesorio, y sus valores incluyen sesión, módulo, clase, función, paquete, etc.

1. 4. 2. El alcance diferencia entre clase y función en el alcance

1. La función en el alcance es equivalente a setup_function en el nivel de función y setup_method en el nivel de clase

2. Probemos la diferencia entre clase y función en el alcance:

2.1, scope='class', el código de ejemplo es el siguiente:

import pytest

@pytest.fixture(scope='class')
# @pytest.fixture(scope='function')
def data1():
    a = 2
    print('----data1----')
    return a

def test_1(data1):
    sum = 1 + data1
    print(sum)
    print('----test1----')

class Test_1():
    def test_2(self, data1):
        sum = 2 + data1
        print(sum)
        print('---test2_1---')

    def test_1(self, data1):
        sum = 3+data1
        print(sum)
        print('---test2_2---')

def test_2(data1):
    sum = 4+data1
    print(sum)
    print('----test2----')

if __name__ == '__main__':
    pytest.main()

 2.2 Resultado de la ejecución: (los datos de tipo de clase solo se ejecutan una vez data1, pero los datos se pueden pasar a todas las funciones de la clase; los casos de uso de tipo de función se ejecutarán una vez)

3.1, scope='function', el código de ejemplo es el siguiente:

import pytest

# @pytest.fixture(scope='class')
@pytest.fixture(scope='function')
def data1():
    a = 2
    print('----data1----')
    return a

def test_1(data1):
    sum = 1 + data1
    print(sum)
    print('----test1----')

class Test_1():
    def test_2(self, data1):
        sum = 2 + data1
        print(sum)
        print('---test2_1---')

    def test_1(self, data1):
        sum = 3+data1
        print(sum)
        print('---test2_2---')

def test_2(data1):
    sum = 4+data1
    print(sum)
    print('----test2----')

if __name__ == '__main__':
    pytest.main()

3.2 Los resultados de la ejecución son los siguientes: (actuando sobre funciones, todas las funciones en el caso de prueba tipo se ejecutarán una vez; los casos de prueba tipo función también se ejecutarán una vez)

4. Resumen: La diferencia entre función y clase: si los dos se aplican a la función de prueba, ambos son equivalentes y ambos representan la creación de un nuevo objeto de firmware, si es para el método de prueba en la clase, la función representa cada uno prueba El método crea un objeto completamente nuevo, y la clase significa que todos los casos de prueba en la clase de prueba comparten un firmware de prueba;

1. 4. 3. La diferencia entre el alcance de la sesión y el alcance del módulo

1. La diferencia entre sesión y módulo: módulo significa que para un módulo, se usa el mismo objeto de firmware en cada módulo, y los objetos de firmware creados por diferentes módulos son diferentes, mientras que sesión significa la sesión completa y los objetos usados ​​por diferentes los módulos también son diferentes;

1.5, gestión de casos de uso de accesorios

1. 5. 1. Omitir caso de uso skip / skipif

1. @pytest.mark.skip(motivo='no ejecutar')

2. Archivo de prueba:

import pytest

@pytest.mark.skip(reason='不执行')
def test_01():
    print('---test1---')

def test_02():
    print('---test2---')

if __name__ == '__main__':
    pytest.main()

3. Resultado de la ejecución:

4. @pytest.mark.skipif(2<3,razón='omitir caso de uso'); archivo de prueba:

import pytest

@pytest.mark.skipif(2<3,reason='跳过用例')
def test_01():
    print('---test1---')

def test_02():
    print('---test2---')

if __name__ == '__main__':
    pytest.main()

 5. Resultado de la ejecución:

1. 5. 2. Marcar fallo xfail

1. Ejemplo de código:

import pytest

def test_01():
    print('---test1---')

@pytest.mark.xfail(reason='跳过')
def test_02():
    print('---test2---')
    assert 1==2

if __name__ == '__main__':
    pytest.main()

2. Resultado de la ejecución:

1. 5. 3. Repetir repetir _

1. Instale primero la biblioteca pytest-repeat, ejecute pip install pytest-repeat

2. Código de muestra: ( especifique el número de veces que se ejecuta el caso de prueba por el método de marca marca )

import pytest

def test_01():
    print('---test1---')
@pytest.mark.repeat(5)
def test_02():
    print('---test2---')
    assert 1==1

if __name__ == '__main__':
    pytest.main(['-s','test_0_1.py'])

3. Resultado de la ejecución:

4. Código de muestra: ( ejecutado por el parámetro ' -- count =5 ' , todos los casos de prueba en el archivo de prueba se ejecutarán 5 veces en secuencia )

import pytest

def test_01():
    print('---test1---')

# @pytest.mark.ios
# @pytest.mark.repeat(5)
def test_02():
    print('---test2---')
    assert 1==1

if __name__ == '__main__':
    pytest.main(['-s', 'test_0_1.py', '--count=5'])  # 会对该测试文件里的所有测试用例都执行5次

 5. Resultado de la ejecución: ( después de que el caso de uso 1 se ejecuta 5 veces , el caso de uso 2 se ejecuta 5 veces más )

6. Puede usar el parámetro ' --repeat-scope= session ' para especificar el alcance repetido ( similar al alcance del accesorio ) , código de muestra:

import pytest

def test_01():
    print('---test1---')

# @pytest.mark.ios
# @pytest.mark.repeat(5)
def test_02():
    print('---test2---')
    assert 1==1

if __name__ == '__main__':
    pytest.main(['-s', 'test_0_1.py', '--count=5', '--repeat-scope=session'])  # 整个文件的用例执行五次

 7. Resultado de la ejecución: ( el caso de uso de todo el archivo se ejecuta cinco veces )

8. Combinando los parámetros --count =10000 y -X, en el número especificado de ejecuciones repetidas, si la ejecución del primer caso de uso falla, se detendrá y continuará ejecutándose ;

9. Resumen de alcance de repetición :

9.1, función: parámetro predeterminado, el alcance de la acción es ejecutar el siguiente caso de prueba después de la ejecución repetida de cada caso de prueba;

9.2, clase: Indica que los casos de uso en la clase se ejecutan repetidamente en unidades de conjuntos de casos de uso;

9.3, módulo: Indica que los casos de uso en el módulo se ejecutan repetidamente en unidades de módulos;

9.4, sesión: Indica que toda la sesión de prueba se usa como una unidad, es decir, todas las pruebas recopiladas se ejecutan una vez y luego todos los casos de uso se ejecutan una vez;

1.6 Mecanismo de afirmación del accesorio

1. 6. 1. Afirmaciones comunes _

1. Afirmaciones comunes:

1.1 afirmar XX: juzgar que XX es verdadero;

1.2, afirmar no XX: juzgar que XX no es cierto;

1.3 afirmar a en b: juzgar que b contiene a;

1.4, afirmar a==b: juzgar que a es igual a b;

1.5 afirmar a !=b: juzgar que a no es igual a b;

2. Código de ejemplo:

import pytest

class Test_a():

    def test_1(self):
        assert 1

    def test_2(self):
        assert 'sh' in 'shell'

    def test_3(self):
        assert 1==1

    def test_4(self):
        assert 'shell' != 'shell_1'

if __name__ == '__main__':
    pytest.main(['-s','test_1.py'])

3. Resultado de la ejecución:

1.7 Use el decorador pytest.ficture para transportar parámetros

1. 7. 1. Utilice los parámetros de parámetro en el objeto de prueba de firmware

1. Código de muestra:

import pytest

class Calculater():
    def add(self,a,b):
        return a+b

@pytest.fixture(scope='function', params=[[1,2,3],[2,3,5]])
def get_data(request):
    # print(Calculater())
    # print(request.param)
    return Calculater(), request.param

def test_add(get_data):
    print(get_data[1][0], get_data[1][1], get_data[1][2])
    assert get_data[0].add(get_data[1][0], get_data[1][1]) == get_data[1][2]

if __name__ == '__main__':
    pytest.main(['-s', 'test_2.py'])

 2. Resultados de la prueba:

3. Resumen: si se usa el método params para lograr la parametrización , el nombre del parámetro pasado en el objeto de firmware siempre es request , y el objeto de parámetro debe devolverse , es decir, request.params ;

4. La función parametrizada también se puede colocar directamente en conftest.py, que puede separar el código de inicialización del firmware y el código parametrizado para realizar dos funciones;

5. Archivo conftest.py, código de muestra:

import pytest

class Calculater():
    def add(self, a, b):
        return a+b

@pytest.fixture(scope='function')
def get_data():
    return Calculater()

@pytest.fixture(params=[[1,2,3],[2,2,4]])
def get_data_params(request):
    return request.param

6. Código de prueba:

import pytest


def test_add_1(get_data, get_data_params):
    print(get_data_params[0],get_data_params[1],get_data_params[2])
    assert get_data.add(get_data_params[0],get_data_params[1])==get_data_params[2]

if __name__ == '__main__':
    pytest.main(['-s', 'test_3.py'])

 7. Resultados de la prueba:

 8. También se puede implementar de la siguiente forma, código de muestra:

import pytest

class Calculater_2(object):
    def __init__(self, a, b):
        self.a = a
        self.b = b
    def add(self):
        return self.a+self.b

@pytest.fixture(scope='function', params=[[1,1,2],[3,3,6]])
def get_data_params_2(request):
    return Calculater_2(request.param[0], request.param[1]), request.param[2]

def test_sum(get_data_params_2):
    return get_data_params_2[0].add() == get_data_params_2[1]

if __name__ == '__main__':
    pytest.main(['-s', 'test_4.py', '--disable-warnings'])

9. Resultado de la ejecución:

1. 7. 1. Analice el archivo yaml para transferir datos

1. El archivo yaml es el siguiente: data.yaml

data:
  - [1,1,2]
  - [2,2,4]
  - [3,3,6]

2. Analice el archivo yaml: read_yaml.py

import yaml


def readyaml():
    with open('data.yaml', encoding='utf-8') as f:
        get_yaml = yaml.load(f, Loader=yaml.FullLoader)
    print(get_yaml)
    print(type(get_yaml))
    return get_yaml['data']

# readyaml()

3. archivo conftest.py (cambie params=valor específico al valor analizado de yaml)

import pytest
from demo10.read_yaml import *   # 导入解析yaml得到yaml值的文件
class Calculater():
    def add(self, a, b):
        return a+b

@pytest.fixture(scope='function')
def get_data():
    return Calculater()

@pytest.fixture(params=readyaml())
def get_data_params(request):
    return request.param

 4. Archivo de prueba: test_4.py

import pytest



def test_add_1(get_data, get_data_params):
    print(get_data_params[0],get_data_params[1],get_data_params[2])
    assert get_data.add(get_data_params[0],get_data_params[1])==get_data_params[2]

if __name__ == '__main__':
    pytest.main(['-s', 'test_3.py'])

5. Ejecute el archivo test_4.py para obtener el resultado:

1. 8. marca marca personalizada

1. 8. 1. Personalice los casos de prueba de marcas y ejecute los casos de prueba de acuerdo con las marcas

1. Ejemplo de código: (5 casos de prueba están marcados de manera diferente, el caso de uso 1 está marcado como: L1; los casos de uso 2 y 3 están marcados como: apple; los casos de uso 4 y 5 están marcados como: case1)

import pytest

@pytest.mark.L1
def test_1():
    print('---test1---')

@pytest.mark.apple
def test_2():
    print('---test2---')

@pytest.mark.apple
def test_3():
    print('---test3---')

@pytest.mark.case1
def test_4():
    print('---test4---')
@pytest.mark.case1
def test_5():
    print('---test5---')

if __name__ == '__main__':
    pytest.main(['-s', 'test_5.py', '-m case1', '--disable-warnings'])

 2. Resultado de la ejecución: (El resultado a continuación es la ejecución marcada como: caso1)

3. Si desea ejecutar todos los casos de uso marcados como caso1, parámetros en el archivo:

pytest.main([ '-s' 'test_5.py' '-m not case1' '--disable-warnings' ])

Cuando se ejecuta en la terminal , la línea de comando es la siguiente : pytest -s test_5.py -m "not case1" 

Resultados de la:

​​​​​​​

3. Resumen agregue directamente el parámetro ' -m case1 ' o ' -m =case1 ' , ejecute todos los casos de uso excepto la marca seleccionada , al agregar parámetros en el archivo de prueba '-m not case1', al  ejecutar la línea de comando en la terminal : -m "no case1"

Supongo que te gusta

Origin blog.csdn.net/weixin_44701654/article/details/128176992
Recomendado
Clasificación