python - example - pytest setup
¿Cómo configuro y desmonto correctamente mi clase de pytest con pruebas? (5)
Estoy usando selenio para las pruebas de extremo a extremo y no puedo entender cómo usar los métodos
setup_class
y
teardown_class
.
Necesito configurar el navegador en el método
setup_class
, luego realizar un montón de pruebas definidas como métodos de clase y finalmente cerrar el navegador en el método
teardown_clas
.
Pero lógicamente parece una mala solución, porque de hecho mis pruebas no funcionarán con la clase, sino con el objeto.
Paso
self
param dentro de cada método de prueba, para poder acceder a los vars de los objetos:
class TestClass:
def setup_class(cls):
pass
def test_buttons(self, data):
# self.$attribute can be used, but not cls.$attribute?
pass
def test_buttons2(self, data):
# self.$attribute can be used, but not cls.$attribute?
pass
def teardown_class(cls):
pass
E incluso parece no ser correcto crear una instancia de navegador para la clase. Debería crearse para cada objeto por separado, ¿verdad?
Entonces, ¿necesito usar los métodos
__init__
y
__del__
lugar de
setup_class
y
teardown_class
?
Como sugirió @Bruno, el uso de accesorios pytest es otra solución accesible para ambas clases de prueba o incluso para funciones de prueba simples. Aquí hay un ejemplo que prueba las funciones de python2.7 :
import pytest
@pytest.fixture(scope=''function'')
def some_resource(request):
stuff_i_setup = ["I setup"]
def some_teardown():
stuff_i_setup[0] += " ... but now I''m torn down..."
print stuff_i_setup[0]
request.addfinalizer(some_teardown)
return stuff_i_setup[0]
def test_1_that_needs_resource(some_resource):
print some_resource + "... and now I''m testing things..."
Entonces, ejecutar
test_1...
produce:
I setup... and now I''m testing things...
I setup ... but now I''m torn down...
Tenga en cuenta que
stuff_i_setup
está referenciado en el dispositivo, lo que permite que ese objeto se
setup
y
torn down
para la prueba con la que interactúa.
Puede imaginar que esto podría ser útil para un objeto persistente, como una base de datos hipotética o alguna conexión, que debe borrarse antes de que se ejecute cada prueba para mantenerlos aislados.
Cuando escribe "pruebas definidas como métodos de clase" , ¿realmente se refiere a métodos de clase (métodos que reciben su clase como primer parámetro) o simplemente métodos regulares (métodos que reciben una instancia como primer parámetro)?
Como su ejemplo usa
self
para los métodos de prueba, supongo que este último, por lo que solo necesita usar
setup_method
en
setup_method
lugar:
class Test:
def setup_method(self, test_method):
# configure self.attribute
def teardown_method(self, test_method):
# tear down self.attribute
def test_buttons(self):
# use self.attribute for test
La instancia del método de prueba se pasa a
setup_method
y
teardown_method
, pero se puede ignorar si su código de configuración / desmontaje no necesita conocer el contexto de prueba.
Más información se puede encontrar
here
.
También le recomiendo que se familiarice con los accesorios de py.test, ya que son un concepto más poderoso.
Esto podría ayudar http://docs.pytest.org/en/latest/xunit_setup.html
En mi conjunto de pruebas, agrupo mis casos de prueba en clases.
Para la configuración y desmontaje que necesito para todos los casos de prueba en esa clase, utilizo los
setup_class(cls)
clase
setup_class(cls)
y
teardown_class(cls)
.
Y para la configuración y el desmontaje que necesito para cada caso de prueba, uso el
setup_method(method)
y el
setup_method(method)
teardown_method(methods)
Ejemplo:
lh = <got log handler from logger module>
class TestClass:
@classmethod
def setup_class(cls):
lh.info("starting class: {} execution".format(cls.__name__))
@classmethod
def teardown_class(cls):
lh.info("starting class: {} execution".format(cls.__name__))
def setup_method(self, method):
lh.info("starting execution of tc: {}".format(method.__name__))
def teardown_method(self, method):
lh.info("starting execution of tc: {}".format(method.__name__))
def test_tc1(self):
<tc_content>
assert
def test_tc2(self):
<tc_content>
assert
Ahora, cuando ejecuto mis pruebas, cuando comienza la ejecución de TestClass, registra los detalles de cuándo comienza la ejecución, cuándo finaliza la ejecución y lo mismo para los métodos.
Puede agregar otros pasos de configuración y desmontaje que pueda tener en las ubicaciones respectivas.
¡Espero eso ayude!
Según la
finalización de Fixture / ejecución del código de desmontaje, el
uso de
addfinalizer
es "histórico".
Como nota histórica, otra forma de escribir código de desmontaje es aceptando un objeto de solicitud en su función de dispositivo y puede llamar a su request.addfinalizer una o varias veces:
La mejor práctica actual para la configuración y desmontaje es usar el
yield
import pytest
@pytest.fixture()
def resource():
print("setup")
yield "resource"
print("teardown")
class TestResource(object):
def test_that_depends_on_resource(self, resource):
print("testing {}".format(resource))
Ejecutarlo da como resultado
$ py.test --capture=no pytest_yield.py
=== test session starts ===
platform darwin -- Python 2.7.10, pytest-3.0.2, py-1.4.31, pluggy-0.3.1
collected 1 items
pytest_yield.py setup
testing resource
.teardown
=== 1 passed in 0.01 seconds ===
Su código debería funcionar tal como lo espera si agrega decoradores
@classmethod
.
@classmethod
def setup_class(cls):
"Runs once per class"
@classmethod
def teardown_class(cls):
"Runs at end of class"
Ver http://pythontesting.net/framework/pytest/pytest-xunit-style-fixtures/