¿Cómo implementar pruebas paramétricas en Python 1-Pea Flower?

¿Cómo implementar pruebas parametrizadas en Python?

Antes, transferí una serie de artículos de marcos de prueba de unidad, que introdujeron los tres marcos de prueba de Python más populares, unittest, nose / nose2 y pytest.

Este artículo quiere centrarse en un escenario de prueba muy común en las pruebas, es decir, las pruebas parametrizadas, seguir hablando sobre el tema de las pruebas e intentar conectar estos marcos de prueba en serie para hacer una comparación horizontal y profundizar la comprensión.

1. ¿Qué es una prueba parametrizada?

Para las pruebas ordinarias, un método de prueba solo necesita ejecutarse una vez, mientras que para un método de prueba, una prueba parametrizada puede necesitar pasar una serie de parámetros y luego realizar múltiples pruebas.

Por ejemplo, si queremos probar la función de inicio de sesión de un sistema, es posible que tengamos que pasar diferentes nombres de usuario y contraseñas para la prueba: use un nombre de usuario que contenga caracteres ilegales, use un nombre de usuario no registrado, use un nombre de usuario extra largo, Use la contraseña incorrecta, use datos razonables, etc.

La prueba paramétrica es un tipo de "Prueba basada en datos", que prueba diferentes parámetros en el mismo método para cubrir los resultados de todas las posibles ramas esperadas. Sus datos de prueba pueden separarse del comportamiento de la prueba, colocarse en archivos, bases de datos o medios externos y luego ser leídos por el programa de prueba.

2. La realización de pruebas parametrizadas?

En términos generales, un método de prueba es una unidad de prueba mínima, y ​​su función debe ser lo más atómica y singular posible.

Echemos un vistazo a dos ideas para implementar pruebas parametrizadas: una es escribir un método de prueba que atraviese todos los parámetros de prueba dentro de ella; la otra es escribir la lógica de los parámetros transversales fuera del método de prueba, y luego llamar a esto a su vez Método de prueba.

Estas dos ideas pueden lograr el propósito de probar, en negocios simples, no hay problema. Sin embargo, de hecho, todos tienen una sola unidad de prueba, y no son optimistas al contar el número de casos de prueba o al generar informes de prueba. La escalabilidad también es un problema.

Entonces, ¿cómo resuelve este problema el marco de prueba existente?

Todos usan decoradores. La idea principal es usar el método de prueba original (como test ()) para generar múltiples métodos de prueba nuevos (como test1 (), test2 () ...), y asignar los parámetros a cada uno por turno. Ellos.

Debido a que los marcos de prueba generalmente cuentan una unidad de prueba como una "prueba", esta idea de "más de una vida" tiene una gran ventaja en los resultados de las pruebas estadísticas en comparación con las dos ideas anteriores.

3. ¿Cómo usar la prueba parametrizada?

La biblioteca estándar de Python en unittest sí misma no admite pruebas parametrizadas. Para resolver este problema, alguien ha desarrollado específicamente dos bibliotecas: una es una ddt y la otra parameterized .

ddt resulta ser una abreviatura de "Pruebas basadas en datos". Uso típico:

import unittest
from ddt import ddt,data,unpack

@ddt
class MyTest(unittest.TestCase):
    @data((3, 1), (-1, 0), (1.2, 1.0))
    @unpack
    def test_values(self, first, second):
        self.assertTrue(first > second)

unittest.main(verbosity=2)

Los resultados de la operación son los siguientes:

test_values_1__3__1_ (__main__.MyTest) ... ok
test_values_2___1__0_ (__main__.MyTest) ... FAIL
test_values_3__1_2__1_0_ (__main__.MyTest) ... ok

==================================================
FAIL: test_values_2___1__0_ (__main__.MyTest)
--------------------------------------------------
Traceback (most recent call last):
  File "C:\Python36\lib\site-packages\ddt.py", line 145, in wrapper
    return func(self, *args, **kwargs)
  File "C:/Users/pythoncat/PycharmProjects/study/testparam.py", line 9, in test_values
    self.assertTrue(first > second)
AssertionError: False is not true

----------------------------------------------
Ran 3 tests in 0.001s

FAILED (failures=1)

El resultado muestra que hay 3 pruebas, y muestra el estado de ejecución y la información de falla de aserción en detalle.

Cabe señalar que cada una de las tres pruebas tiene un nombre, y el nombre también contiene información sobre sus parámetros. El método test_values ​​original desapareció y se dividió en tres.

En el ejemplo anterior, la biblioteca ddt usa tres decoradores (@ddt, @data, @unpack), lo cual es realmente feo. Echemos un vistazo a la biblioteca parametrizada relativamente mejor:

import unittest
from parameterized import parameterized

class MyTest(unittest.TestCase):
    @parameterized.expand([(3,1), (-1,0), (1.5,1.0)])
    def test_values(self, first, second):
        self.assertTrue(first > second)

unittest.main(verbosity=2) 

Los resultados de la prueba son los siguientes:

test_values_0 (__main__.MyTest) ... ok
test_values_1 (__main__.MyTest) ... FAIL
test_values_2 (__main__.MyTest) ... ok

=========================================
FAIL: test_values_1 (__main__.MyTest)
-----------------------------------------
Traceback (most recent call last):
  File "C:\Python36\lib\site-packages\parameterized\parameterized.py", line 518, in standalone_func
    return func(*(a + p.args), **p.kwargs)
  File "C:/Users/pythoncat/PycharmProjects/study/testparam.py", line 7, in test_values
    self.assertTrue(first > second)
AssertionError: False is not true

----------------------------------------
Ran 3 tests in 0.000s

FAILED (failures=1)

Esta biblioteca solo usa un decorador @ parametrizado.expandir, que es mucho más refrescante.

También recordó que el método de prueba original ha desaparecido, reemplazado por tres nuevos métodos de prueba, pero las reglas de denominación del nuevo método son diferentes del ejemplo de ddt.

Después de presentar unittest, mira los muertos nose y los nuevos nose2 . El marco de la nariz es una prueba unitaria con complementos. Los usos anteriores son los mismos.

Además, la propia implementación parametrizada también se proporciona en nose2:

import unittest
from nose2.tools import params

@params(1, 2, 3)
def test_nums(num):
    assert num < 4

class Test(unittest.TestCase):
    @params((1, 2), (2, 3), (4, 5))
    def test_less_than(self, a, b):
    assert a < b

Finalmente, echemos un vistazo al marco de pytest, que implementa pruebas parametrizadas como esta:

import pytest

@pytest.mark.parametrize("first,second", [(3,1), (-1,0), (1.5,1.0)])
def test_values(first, second):
    assert(first > second)

Los resultados de la prueba son los siguientes:

==================== test session starts ====================
platform win32 -- Python 3.6.1, pytest-5.3.1, py-1.8.0, pluggy-0.13.1
rootdir: C:\Users\pythoncat\PycharmProjects\study collected 3 items

testparam.py .F
testparam.py:3 (test_values[-1-0])
first = -1, second = 0

    @pytest.mark.parametrize("first,second", [(3,1), (-1,0), (1.5,1.0)])
    def test_values(first, second):
>       assert(first > second)
E       assert -1 > 0

testparam.py:6: AssertionError
.                                                         [100%]

========================= FAILURES ==========================
_________________________ test_values[-1-0] _________________________

first = -1, second = 0

    @pytest.mark.parametrize("first,second", [(3,1), (-1,0), (1.5,1.0)])
    def test_values(first, second):
>       assert(first > second)
E       assert -1 > 0

testparam.py:6: AssertionError
===================== 1 failed, 2 passed in 0.08s =====================
Process finished with exit code 0

Todavía tenemos que recordar a todos que pytest también ha cambiado de uno a tres, pero no podemos ver la información sobre el método recién nombrado. ¿Esto significa que no genera nuevos métodos de prueba? ¿O simplemente ocultar la información del nuevo método?

4. El resumen final

Lo anterior introdujo el concepto de prueba paramétrica, ideas de implementación y métodos de uso en los tres marcos de prueba principales de Python. Usé solo el ejemplo más simple para la rápida divulgación científica.

Sin embargo, este tema aún no ha terminado. Para las bibliotecas que mencionamos que se pueden parametrizar, además de la diferencia por escrito, ¿qué diferencia tendrán en el nivel de código específico?

Específicamente, ¿cómo convierten un método en múltiples métodos y vinculan cada método con los parámetros correspondientes? En la implementación, ¿qué problemas difíciles deben resolverse?

Al analizar algún código fuente, encontré este tema bastante interesante, así que planeo escribir otro artículo. Entonces, este artículo ha terminado, gracias por leer

17 artículos originales publicados · Me gusta1 · Visitas 818

Supongo que te gusta

Origin blog.csdn.net/weixin_45433031/article/details/105518902
Recomendado
Clasificación