[Pruebas automatizadas] Pytest+Appium+Allure para hacer esas cosas de la automatización de la interfaz de usuario

El texto presenta principalmente algunos procesos y experiencias registrados por Pytest+Allure+Appium.

¿Qué utiliza principalmente la ley?

Python3
Appium
Allure-pytest
Pytest
Appium Método poco común pero fácil de usar
Appium ejecuta directamente el método adb shell
# Agregue el parámetro --relaxed-security Appium cuando Appium comience a ejecutar un método similar al adb shell
> appium -p 4723 --relaxed- seguridad

# Usar el método
def adb_shell(self, command, args, includeStderr=False):
"""
appium --relaxed-security way to start
adb_shell('ps',['|','grep','android'])

:param command:command
:param args:parameter
:param includeStderr: si es True, se lanzará una excepción
:return:
"""
result = self.driver.execute_script('mobile: shell', { 'command': command , 'args': args, 'includeStderr': includeStderr, 'timeout': 5000 }) return result['stdout']





Método de Appium para interceptar directamente imágenes de elementos
element = self.driver.find_element_by_id('cn.xxxxxx:id/login_sign')
pngbyte = element.screenshot_as_png
image_data = BytesIO(pngbyte)
img = Image.open(image_data)
img.save('element .png')
# Este método puede obtener directamente la captura de pantalla del área del botón de inicio de sesión

Appium obtiene directamente el registro en el teléfono móvil
# Después de usar este método, el caché de logcat en el teléfono móvil se borrará y se restablecerá a cero, y se registrará nuevamente
# Se recomienda limpiar después de ejecutar cada caso de uso y luego guardar y reduzca la salida del registro antiguo cuando haya un error
# Android
logcat = self.driver.get_log('logcat')

# iOS necesita instalar brew install libimobiledevice
logcat = self.driver.get_log('syslog')

# web get console log
logcat = self.driver.get_log('navegador')

c = '\n'.join([i['message'] for i in logcat])
allure.attach(c, 'APPlog', allure.attachment_type.TEXT)
#escribir en el informe de prueba de allure

Appium transfiere archivos directamente al dispositivo
# Enviar archivo
#Android
driver.push_file('/sdcard/element.png', source_path='D:\works\element.png')

# Obtenga el archivo del teléfono
png = driver.pull_file('/sdcard/element.png')
with open('element.png', 'wb') as png1:
png1.write(base64.b64decode(png))

# Obtenga la carpeta del teléfono móvil y exporte la
carpeta del archivo zip = driver.pull_folder('/sdcard/test')
with open('test.zip', 'wb') as folder1:
folder1.write(base64.b64decode(folder ) )

# iOS
# Necesita instalar ifuse
# > brew install ifuse o > brew cask install osxfuse o busque el método de instalación usted mismo

driver.push_file('/Documentos/xx/elemento.png', source_path='D:\works\element.png')

# Enviar archivos a la zona de pruebas de la aplicación
# Después de iOS 8.3, la aplicación debe habilitar el permiso UIFileSharingEnabled; de lo contrario, se informará un error
bundleId = 'cn.xxx.xxx' # Nombre de la aplicación
driver.push_file('@{bundleId}/Documents /xx/element.png' .format(bundleId=bundleId), source_path='D:\works\element.png')

La diferencia entre la inicialización de Pytest y Unittest.
Muchas personas han usado unitest. Permítanme hablar sobre algunas diferencias entre pytest y unitest en el método Hook.


1. Pytest es similar a unitest, con algunas diferencias, la siguiente es la clase Pytest TestExample:
def setup(self):
print("setup class:TestStuff")

def teardown(self):
print ("clase de desmontaje: TestStuff")

def setup_class(cls):
print ("setup_class class:%s" % cls.__name__)

def teardown_class(cls):
print ("teardown_class class:%s" % cls.__name__)

def setup_method(self, method):
print ("setup_method method:%s" % method.__name__)

def teardown_method(self, method):
print ("teardown_method method:%s" % method.__name__)

2.使用 pytest.fixture()
@pytest.fixture()
def driver_setup(solicitud):
request.instance.Action = DriverClient().init_driver('android')
def driver_teardown():
request.instance.Action.quit()
solicitud.addfinalizer(driver_teardown)

Inicialice el
método de la instancia 1.setup_class para llamar a
la clase Singleton(objeto):
"""Singleton
ElementActions encapsula la clase de operación por sí misma"""
Acción = Ninguna

def __nuevo__(cls, *args, **kw):
si no hasattr(cls, '_instancia'):
wish_caps={}
host = "http://localhost:4723/wd/hub"
driver = webdriver.Remote(host , gorras_deseadas)
Acción = ElementActions(controlador, gorras_deseadas)
orig = super(Singleton, cls)
cls._instance = orig.__new__(cls, *args, **kw)
cls._instance.Action = Action
return cls._instance

clase DriverClient(Singleton):
pasar

Llamado en el caso de prueba

class TestExample:
def setup_class(cls):
cls.Action = DriverClient().Action

def teardown_class(cls):
cls.Action.clear()


def test_demo(self)
self.Action.driver.launch_app()
self.Action.set_text('123')

2. pytest.fixture() llama a
la clase DriverClient():

def init_driver(self,device_name):
wish_caps={}
host = "http://localhost:4723/wd/hub"
driver = webdriver.Remote(host, wished_caps)
Action = ElementActions(driver, wished_caps)
return Action

# Esta función debe colocarse en conftest.py, y pytest recogerá automáticamente
@pytest.fixture()
def driver_setup(request):
request.instance.Action = DriverClient().init_driver()
def driver_teardown():
request. instancia Action.clear()
request.addfinalizer(driver_teardown)

Llamado en el caso de prueba

#El decorador introducirá directamente la función driver_setup
@pytest.mark.usefixtures('driver_setup')
class TestExample:

def test_demo(self):
self.Action.driver.launch_app()
self.Action.set_text('123')

Método de parametrización de Pytest
1. El primer método parametriza el método de parametrización del decorador
@pytest.mark.parametrize(('kewords'), [(u"Xiaoming"), (u"Xiaohong"), (u"Xiaobai ")]) def
test_kewords (self,palabras clave):
print(palabras clave)

# 多个参数
@pytest.mark.parametrize("test_input,esperado", [
("3+5", 8),
("2+4", 6),
("6*9", 42),
])
def test_eval(test_input, esperado):
afirmar eval(test_input) == esperado

2. El segundo método es usar el gancho pytest para agregar parametrización en lotes
# conftest.py
def pytest_generate_tests(metafunc):
"""
Use el gancho para agregar parámetros al caso de uso
metafunc.cls.params correspondiente al parámetro params en el clase

"""
intente:
if metafunc.cls.params y metafunc.function.__name__ in metafunc.cls.params: ## 对应 TestClass params
funcarglist = metafunc.cls.params[metafunc.function.__name__]
argnames = list(funcarglist[0 ])
metafunc.parametrize(argnames, [[funcargs[name] for name in argnames] for funcargs in funcarglist])
excepto AttributeError:
pass

# test_demo.py
class TestClass:
"""
:params 对应 hook 中 metafunc.cls.params
"""
# params = Parametrizar('TestClass.yaml').getdata()

parámetros = { 'prueba_a': [{'a': 1, 'b': 2}, {'a': 1, 'b': 2}], 'prueba_b': [{'a': 1, ' b': 2}, {'a': 1, 'b': 2}], } def test_a(self, a, b): afirmar a == b def test_b(self, a, b): afirmar a = = segundo






Dependencias de casos de uso de Pytest
Utilice la biblioteca de dependencias de pytest para crear dependencias
Cuando el caso de uso de nivel superior falla, los casos de uso de dependencia posteriores se omitirán directamente y podrá filtrar entre clases
. para copiar el archivo site-packages/pytest_dependency.py de

clase DependencyManager(objeto):
"""Administrador de dependencias, almacena los resultados de las pruebas.
"""

ScopeCls = {'módulo':pytest.Módulo, 'sesión':pytest.Sesión}

@classmethod
def getManager(cls, item, scope='session'): # Cámbielo a sesión aquí

si

> pip install pytest-dependencia

clase TestExample(objeto):

@pytest.mark.dependency()
def test_a(self):
afirmar Falso

@pytest.mark.dependency()
def test_b(self):
afirmar Falso

@pytest.mark.dependency(depends=["TestExample::test_a"])
def test_c(self):
# Si TestExample::test_a falla, el caso de uso no se ejecutará
# Puede filtrar entre clases
print("Hola, soy en prueba_c ")

@pytest.mark.dependency(depende=["TestExample::test_a","TestExample::test_b"])
def test_d(self):
print("Hola, estoy en test_d")

pytest -v test_demo.py
2 falló
- test_1.py:6 TestExample.test_a
- test_1.py:10 TestExample.test_b
2 omitido

Marca personalizada de Pytest para realizar la detección de casos de uso
1. Use el módulo @pytest.mark para marcar clases o funciones para la detección al ejecutar casos de uso
@pytest.mark.webtest
def test_webtest():
pass


@pytest.mark.apitest
class TestExample(objeto):
def test_a(self):
pasar

@pytest.mark.httptest
def test_b(self):
pasar

Ejecutar solo el caso de uso marcado webtest

pytest -v -m webtest

Resultados (0.03s):
1 aprobado
2 deseleccionados

Ejecución marca múltiples casos de uso

pytest -v -m "webtest o apitest"

Resultados (0.05s):
3 aprobados

Solo el caso de uso que no ejecuta el webtest marcado

pytest -v -m "no webtest"

Resultados (0.04s):
2 pasaron
1 deseleccionado

Marcar múltiples casos de uso sin ejecución

pytest -v -m "no webtest y no apitest"

Resultados (0.02s):
3 deseleccionados

2. Seleccione el caso de uso según el nodo de prueba
pytest -v Test_example.py::TestClass::test_a
pytest -v Test_example.py::TestClass
pytest -v Test_example.py Test_example2.py

3. Use el gancho pytest para marcar casos de uso en lotes
# conftet.py

def pytest_collection_modifyitems(items):
"""
Obtenga el nombre de cada función y márquelo cuando el carácter se incluya en el caso de uso
"""
for item in items:
if "http" in item.nodeid:
item.add_marker(pytest .mark.http )
elif "api" en item.nodeid:
item.add_marker(pytest.mark.api)

clase TestExample(objeto):
def test_api_1(self):
pasar

def test_api_2(auto):
aprobado

def test_http_1(auto):
aprobado

def test_http_2(auto):
aprobado
def test_demo(auto):
aprobado

Ejecutar solo el caso de uso de la API etiquetada

pytest -v -m api
Resultados (0.03s):
2 aprobados
3 deseleccionados
Puede ver que después de usar el marcado por lotes, solo se ejecuta el método con api en el caso de prueba

Use capturas de pantalla de manejo de errores de casos, registros de aplicaciones, etc.
1. El primer método que usa el decorador de funciones de Python

def monitorapp (función):
"""
Decorador de casos de uso, captura de pantalla, registro, si se debe omitir, etc.
Obtenga el registro del sistema, logcat de Android, ios use syslog
"""

@wraps(function)
def wrapper(self, *args, **kwargs):
try:
allure.dynamic.description('Use case start time: {}'.format(datetime.datetime.now()))
function(self , *args, **kwargs)
self.Action.driver.get_log('logcat')
excepto Excepción como E:
f = self.Action.driver.get_screenshot_as_png()
allure.attach(f, 'Failed screenshot', allure.attachment_type . PNG)
logcat = self.Action.driver.get_log('logcat')
c = '\n'.join([i['message'] for i in logcat])
allure.attach(c, 'APPlog', allure .attachment_type.TEXT)
raise E
finalmente:
if self.Action.get_app_pid() != self.Action.Apppid:
raise Exception('El ID de proceso del dispositivo cambia, puede ocurrir un bloqueo')
return wrapper

2. El segundo método para usar pytest hook (elija uno de los otros)

@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_makereport(item, call):
Action = DriverClient().Acción
resultado = yield
rep = result.get_result()
if rep.when == "llamar" y rep. falló:
f = Action.driver.get_screenshot_as_png()
allure.attach(f, 'captura de pantalla fallida', allure.attachment_type.PNG)
logcat = Action.driver.get_log('logcat')
c = '\n'.join([ i['mensaje'] para i en logcat])
allure.attach(c, 'APPlog', allure.attachment_type.TEXT)
if Action.get_app_pid() != Action.apppid:
raise Exception('El ID de proceso del dispositivo cambia, puede Ocurrió un accidente')

Cómo usar otros ganchos en Pytest
1. Personalizar los parámetros de Pytest
> pytest -s -all

# contenido de conftest.py
def pytest_addoption(parser):
"""
自定义参数
"""
parser.addoption("--all", action="store_true",default="type1",help="ejecutar todas las combinaciones" )

def pytest_generate_tests(metafunc):
if 'param' in metafunc.fixturenames:
if metafunc.config.option.all: # Aquí puede obtener parámetros personalizados
paramlist = [1,2,3]
else:
paramlist = [1,2, 4 ]
metafunc.parametrize("param",paramlist) # Agregar parametrización al caso de uso

# ¿Cómo obtener parámetros personalizados en casos de prueba?
# contenido de conftest.py
def pytest_addoption(parser):
"""
Parámetros personalizados
"""
parser.addoption("--cmdopt", action="store_true",default= "type1 ",ayuda="ejecutar todas las combinaciones")


@pytest.fixture
def cmdopt(solicitud):
return request.config.getoption("--cmdopt")


# test_sample.py
def test_sample(cmdopt):
if cmdopt == "tipo1":
print("primero")
elif cmdopt == "tipo2":
print("segundo")
afirmar 1

> pytest -q --cmdopt=type2
segundo
.
1 pasó en 0.09 segundos

2. Directorio de prueba de filtro Pytest
#Filtrar la carpeta o el nombre del archivo que pytest necesita ejecutar
def pytest_ignore_collect(ruta,config):
si 'logcat' en ruta.dirname:
return True #Return True, el archivo no se ejecutará

Algunos métodos comunes de Pytest
Prioridad de caso de uso de Pytest (como inicio de sesión prioritario o algo así)
> pip install pytest-ordering

@pytest.mark.run(order=1)
class TestExample:
def test_a(self):

Reintento de error de caso de uso de Pytest
#Método original
pytet -s test_demo.py
pytet -s --lf test_demo.py #Al ejecutar por segunda vez, solo se ejecutarán los casos de uso fallidos
pytet -s --ll test_demo.py #Segunda ejecución
, todos los casos de uso se ejecutarán, pero los casos de
falla se ejecutarán primero

Otros parámetros comunes de Pytest
pytest --maxfail=10 #Detener la ejecución de pytest si el error supera las 10 veces
pytest -x test_demo.py #Detener si se produce un error

En términos de arreglos de aprendizaje,
como una persona que ha estado allí, espero que todos eviten algunos desvíos. Si no quieres experimentar la sensación de no poder encontrar información cuando aprendes, nadie responde preguntas y da después de unos días de persistencia, aquí compartiré con ustedes algo de automatización. Los recursos de aprendizaje de la prueba esperan ayudarlo en el camino. 【Garantizado 100% Gratis】

Cómo obtener el archivo de vídeo:

Este documento y material de video debe ser el almacén de preparación más completo y completo para los amigos que quieran participar en [pruebas de software] Este almacén también me ha acompañado a través del viaje más difícil, ¡y espero que pueda ayudarlo a usted también! Todo lo anterior se puede compartir y puede recibirlo usted mismo haciendo clic en la pequeña tarjeta a continuación.

Supongo que te gusta

Origin blog.csdn.net/2301_76643199/article/details/131141930
Recomendado
Clasificación