Платформа тестирования Pytest и Allure — супердетализированная версия + практический бой
Платформа тестирования Pytest и Allure — супердетализированная версия + практический бой

Всем привет, мы снова встретились, я ваш друг Цюаньчжаньцзюнь.

Каталог статей

1. Введение, установка, структура фреймворка и метод выполнения pytest.

**

1. Особенности

:1. Простой, гибкий и простой в использовании; поддерживает параметризацию; тествариант использованияизskipиxfail иметь дело с; 2. Он может поддерживать простое модульное тестирование и сложное функциональное тестирование, а также может использоваться для Автоматизированное тестирование, такое как Selenium/Appium и автоматическое тестирование интерфейса. (pytest+requests); 3. pytest имеет множество сторонних плагинов, его можно настраивать и расширять. лучше Используется как pytest-allure (генерация идеального отчета о тестировании в формате HTML) pytest-xdist (многопроцессорное распределение) и т. д.; 4. Может хорошо интегрироваться с Jenkins;** 5. **

2. Установка

: установка pytest, импорт связанных зависимых библиотек. Pip install –U pytest U означает обновление Пип установить сахар pip install pytest-rerunfailures Pip установить pytest-xdist Pip install pytest-предполагать Pip intall pytest-html… Просмотр списка пипсов pytest -h помощь**

3. Структура фреймворка pytest

Структура фреймворка Pytest Импорт pytest аналогичен настройке, демонтаж также более гибок, а также есть session().

уровень модуля (setup_module/ teardown_module) Функции, не входящие в класс, полезны функциональный уровень (setup_function/ teardown_function) Функции, не входящие в класс, полезны уровень класса (setup_class/ Teardown_class) только в Пробегите один раз до и после занятия. уровень метода (setup_method/ teardown_methond) Начало и конец методов, выполняемых в классе

4. Метод исполнения

Как выполняется pytest Pytest/py.test (терминал, командная строка, pycharm можно настроить для выполнения в режиме pytest)

  1. Pytest –v (информация самого высокого уровня — подробный)
  2. pytest -v -s filename 3.Pytest-q (тишина) (выходная печать) Несколько методов выполнения 1.pytest запустит тест в текущем каталоге и его подкаталогах. _ * .py или * тип test.py Все файлы в формате. 2. Функции, начинающиеся с test_, классы, начинающиеся с Test, и методы, начинающиеся с test_. Все пакеты packageВсе должны иметь__init_.pyдокумент。 3.Pytest может выполнять варианты использования и методы, написанные в рамках unittest.

2. Pytest — подтвердить, пропустить и запустить

1. Pytest – подтвердить, пропустить и запустить

2. пропустить метку (пропустить)

3. xfail в отметке (неудача)

pytest.xfail() Мы уже узнали, как пропустить выполнение тестовых случаев. Один из способов — использовать метод pytest.skip() в тестовой функции. pytest.xfail(), который мы собираемся сейчас изучить, чем-то похож на pytest.skip(), за исключением того, что его смысл таков: пометить вариант использования как сбой xfail, и последующий код в варианте использования не будет выполнен.

Соблюдаются старые правила: когда мы вызываем метод pytes.xfail() в тестовом примере, мы можем передать параметр причины, чтобы указать причину.

Язык кода:javascript
копировать
Файл #test_Pytest.py
#coding=utf-8

import pytest

class Test_Pytest():

        def test_one(self,):
                print("----start------")
                pytest.xfail(reason='Эта функция не завершена')
                print("выполнение метода test_one" )
                assert 1==1

        def test_two(self):
                print("выполнение метода test_two" )
                assert "o" in "love"

        def test_three(self):
                print("выполнение метода test_three" )
                assert 3-2==1

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

Результаты выполнения показаны ниже: Мы видим, что код перед методом pytest.xfail() в этом варианте использования запускается, а последующие больше не запускаются в результате, однажды вариант использования помечается как; xfail.

Этот метод позволяет нам напрямую пометить вариант использования как неудачный. Итак, при каких обстоятельствах мы будем это делать? Функция не завершена и имеет известные проблемы. Кроме того, для выполнения варианта использования требуются предварительные условия или операции. Если предварительные условия или операции не выполняются, мы можем напрямую установить вариант использования как неудачный, то есть xfail.

@pytest.mark.xfail В дополнение к pytest.xfail(), описанному выше, есть еще один способ использования xfai. Это тег @pytest.mark.xfail. Его значение заключается в том, что ожидается, что тестовый пример завершится неудачно, но это не повлияет на его выполнение. Если тестовый пример не удается выполнить, результатом является xfail (дополнительное сообщение об ошибке не отображается), если тестовый пример выполняется успешно, результатом является xpass.

Съешьте личи: мы напрямую добавляем тег @pytest.mark.xfail в тестовый пример.

Язык кода:javascript
копировать
Файл #test_Pytest.py
#coding=utf-8

import pytest

class Test_Pytest():

        @pytest.mark.xfail
        def test_one(self):
                print("выполнение метода test_one" )
                assert 1==2

        def test_two(self):
                print("выполнение метода test_two" )
                assert "o" in "love"

        def test_three(self):
                print("выполнение метода test_three" )
                assert 3-2==1

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

Результат выполнения показан ниже: вы можете видеть, что отмеченный нами вариант использования действительно выполнился, поскольку утверждение не выполнено, результат — xfailed, а случай ошибки и конкретная информация не отображаются как обычно;

Мы изменили утверждение на правильное и запустили его еще раз. Результат следующий: хотя наш вариант использования прошел нормально, он все равно был помечен как xpassed, а не как пройденный.

4. Используйте пользовательские маркеры, чтобы выполнять только часть вариантов использования.

1. отметка В следующем случае отметьте test_send_http() как webtest.

Язык кода:javascript
копировать
# content of test_server.py

import pytest

@pytest.mark.webtest
def test_send_http():
    pass # perform some webtest test for your app

def test_something_quick():
    pass

def test_another():
    pass

class TestClass:
    def test_method(self):
        pass

if __name__ == "__main__":
    pytest.main(["-s", "test_server.py", "-m=webtest"])
Запускать только с отметкой webtest istest, при запуске cmd из добавить -m параметр,указанное значение параметра

```py
pytest -v -m webtest

Если вы не хотите выполнять тестовый пример с пометкой «webtest», используйте «not webtest».

Язык кода:javascript
копировать
pytest -v -m “not webtest”
Язык кода:javascript
копировать
import pytest

@pytest.mark.webtest
def test_send_http():
    pass # perform some webtest test for your app
def test_something_quick():
    pass
def test_another():
    pass
class TestClass:
    def test_method(self):
        pass

if __name__ == "__main__":
    pytest.main(["-s", "test_server.py", "-m='not webtest'"])

5. Метод имени класса имени файла выполняет некоторые варианты использования.

2.-v Указанный идентификатор функционального узла Если вы хотите указать вариант использования в классе в определенном модуле .py, например вариант использования testmethod в TestClass Для каждого варианта использования, который начинается с test (или заканчивается на _test), именем функции (или метода) является идентификатор узла варианта использования. Используйте -v, чтобы указать идентификатор узла для запуска. параметр

Язык кода:javascript
копировать
pytest -v test_server.py::TestClass::test_method

Конечно, вы также можете запустить весь класс.

Язык кода:javascript
копировать
 pytest -v test_server.py::TestClass

Вы также можете выбрать несколько узлов для запуска и разделить несколько узлов пробелами.

Язык кода:javascript
копировать
pytest -v test_server.py::TestClass test_server.py::test_send_http

Комбинированный вызов 6,-k для выполнения некоторых вариантов использования

.-k Сопоставить название варианта использования Это можно указать с помощью параметра командной строки -k в Сопоставить. название варианта использованияизвыражение

Язык кода:javascript
копировать
pytest -v -k http

Вы также можете запустить все тесты и исключить определенные случаи на основе их названий:

Язык кода:javascript
копировать
pytest -k “not send_http” -v

Вы также можете выбрать одновременное соответствие «http» и «quick».

Язык кода:javascript
копировать
pytest -k “http or quick” -v

3. Pytest-приспособление

Ниже приведены практические детали — приспособления действительно потрясающие.

По сравнению с unittest, самым передовым моментом pytest, вероятно, является механизм фиксации.

Для unittest setUp и TearDown необходимо записать в классе каждого варианта использования. Это то, что мы называем пре- и постпозицией.

Неизбежно, что предварительная и постобработка многих вариантов использования одинакова (например, многие варианты использования требуют входа в систему спереди и выхода сзади), поэтому нам приходится многократно копировать и вставлять, что приводит к увеличению рабочая нагрузка и объем кода. Интерфейс также кажется громоздким.

Итак, в это времяМеханизм фиксации в pytest вот-вот дебютирует.

С точки зрения непрофессионала: приспособление = передняя часть + стойка.

Удобство в том, что если многие варианты использования имеют одинаковый префикс и постфикс, то я могу реализовать только один, а затем просто вызвать нужный вариант использования.

1. Механизм: создайте файл conftest.py на том же уровне, что и тестовый пример, или родительском для тестового примера. 2. В файл conftest.py: поместите все префиксы и постфиксы. Нет необходимости в файле use case.py активно вводить файл conftest. 3. Определить функцию: включая предоперационную + послеоперационную. 4. Объявите функцию как фикстуру :Добавить перед функцией @pytest.fixture(уровень действия = по умолчанию — функция) 5.Определение приспособления.   Если есть возвращаемое значение, напишите его после доходности. (Функция доходности эквивалентна возврату)   В тестовом примере, когда вызывается функция фиксации с возвращаемым значением, имя функции представляет возвращаемое значение.   существоватьтествариант использованиякогдасередина,Имя функции можно использовать в качестве варианта использования.

1. Следующим образом: Определите функцию с именем open_url, которая имеет префикс и префикс к приспособлению. Префикс предназначен для открытия ссылки, а постфикс — для выхода из браузера.

@pytest.fixture(scope="class") #Определение области видимости

Язык кода:javascript
копировать
  def open_url():
    # префикс
    driver = webdriver.Chrome()
    driver.get(url) #url — адрес ссылки
    yield driver    #yieldпредыдущий коддапрефикс,После этого код «Из Задний».
    # Задний
    driver.quit()

Таким образом мы определяем приспособление под названием open_url.

2. Перед классом, который мы хотим использовать этот префикс и постфикс, мы используем @pytest.mark.usefixtures (имя функции фиксатора)

Вы можете напрямую вызвать pre и post, определенные выше

Вы можете видеть, что в классе TestLogin мы больше не пишем настройку и демонтаж. Мы можем просто написать наш промежуточный процесс напрямую. Разве это не очень удобно?

3. Расширенный метод: Определите несколько приборов в conftest. Один прибор может быть префиксом и префиксом другого прибора. В течение этого периода поля по-прежнему используются для разделения префикса и префикса.

Как показано на рисунке выше, вы можете видеть, что мой класс также ссылается на приспособление с именем обновить_страницу. Перейдите непосредственно к коду:

Язык кода:javascript
копировать
# обновить страницу - Определите второй прибор
@pytest.fixture
def refresh_page(open_url):
    yield
    open_url.refresh()

Open_url напрямую используется как предварительная ссылка на другой прибор, разделенный выходом. После того, как предварительная и пост-ссылка open_url выполняются в варианте использования, пост-ссылка обновления выполняется снова. Порядок выполнения: код перед выходом open_url – код варианта использования – код после выхода open_url –> код после выходом обновления_страницы Разве это не чудесно? Это может решить проблему, когда многие процессы вариантов использования взаимосвязаны.

4. Говоря о множественных вызовах фикстур, описанных выше, многие люди задаются вопросом, не будут ли эти фикстуры конфликтовать друг с другом.

Конечно, нет. Устройство уже определило свой домен варианта использования в conftest.py, и оно возьмет на себя инициативу, чтобы определить, в каком домене варианта использования действует ваше устройство. Во-первых, давайте взглянем на определение функции фиксации в рамках:

Область — это область, определяющая область варианта использования: функция: область действия по умолчанию, будет вызываться каждая функция или метод, они будут вызываться, если они не заполнены. класс: вызывается один раз для каждого класса module: Вызывается один раз для каждого файла .py. В файле может быть несколько функций и классов. Сеанс: вызывается один раз несколькими файлами и может охватывать файлы. Например, в файле .py каждый файл .py является модулем. объем: session > module > class > function

Таким образом, различные устройства не будут конфликтовать друг с другом при вызове.

5. Автоматическое применение приспособления autouse.

Пример автоматического вызова: ** Когда существует много вариантов использования управления, этот метод более удобен и эффективен, но вы должны быть осторожны при использовании этой функции и обязательно обращать внимание на область действия фикстуры. Следует отметить, что при использовании этого метода нельзя использовать функцию возвращаемого значения. По умолчанию для autouse установлено значение False. Если по умолчанию установлено значение False, вы можете использовать два вышеуказанных метода для проверки прибора. Если установлено значение True, все тесты будут автоматически вызывать этот прибор. Автоматическое использование соответствует правилуscope="ключевое слово параметр": когдаscope="session", независимо от того, как он определен, он будет запускаться только один раз; когдаscope="module", каждый файл py будет запускаться только один раз, когдаscope="; class", каждый класс запускается только один раз (но когда файл содержит функцию икласс, он будет запускаться один раз для каждой функции (не в классе)); когдаscope="function", каждая функция будет запускаться один раз; ‘’’ Автоматизация ежедневного письмавариант использования Напишу немногопрефиксизfixtureдействовать,Если вариант использования требует ее использования, просто передайте имя функции напрямую. Когда много вариантов использования,Отправлять этот параметр каждый раз,Это будет более хлопотно. Внутри прибора есть параметрautouse,По умолчанию Fasle не включен.,Можно установить значение True, чтобы включить автоматическое использование приборов.,Таким образом, варианту использования не нужно каждый раз передавать параметры.

Установить autouse=True Для autouse установлено значение True для автоматического вызова функции прибора. start устанавливает область на уровне модуля. Он выполняется только один раз в текущем варианте использования .py. autouse=True автоматически использует [picture] open_home для установки области на уровне функции. Вызывается один раз перед каждым вариантом использования, используется автоматически

Язык кода:javascript
копировать
import pytest

@pytest.fixture(scope="module",autouse=True)
def start(request):
    print("\n----Начать выполнение модуля------")
    print('module : %s'% request.module.__name__)
    print('------Запустить браузер-------')
    yield
    print("------Конец теста end!----------")

@pytest.fixture(scope="function",autouse=True)
def open_home(request):
    print("function:%s \n--Вернуться на домашнюю страницу--"% request.function.__name__)

def test_01():
    print('----Случай использования 01-----')

def test_02():
    print('----Сценарий использования 02-----')

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

Результат выполнения

Язык кода:javascript
копировать
----Начать выполнение модуля------
module : autouse
------Запустить браузер-------
function:test_01 
--Вернуться на главную--
.----Сценарий использования 01-----
function:test_02 
--Вернуться на главную--
.---- Вариант использования 02 -----
------Конец теста end!----------

4. Параметризация и реализация инфраструктуры, управляемой данными

Параметризация 1

Язык кода:javascript
копировать
import pytest


@pytest.mark.parametrize('test_input,expected',[('3+5',8),
                         ('2-1',1),('7*5',30)])
def test_eval(test_input,expected):
    assert eval(test_input)==expected    ----eval преобразует строку в выражение


est_param.py::test_eval[2-1-1]
test_param.py::test_eval[7*5-30] PASSED [ 33%]PASSED [ 66%]FAILED [100%]
test_param.py:3 (test_eval[7*5-30])
35 != 30

Expected :30
Actual :35
<Click to see difference>

test_input = '7*5', expected = 30

@pytest.mark.parametrize('test_input,expected',[('3+5',8),
('2-1',1),('7*5',30)])
def test_eval(test_input,expected):
> assert eval(test_input)==expected
E assert 35 == 30          ----Подсказка поменять 30 на 35

test_param.py:7: AssertionError

Assertion failed

Параметризация 2

Язык кода:javascript
копировать
import pytest
test_user_data=['linda','sai','tom']
@pytest.fixture(scope='module')
def login(request):
    user=request.param
    print('Откройте домашнюю страницу и войдите в систему %s'%user)
    return user


#indirect=True означает выполнение входа в систему как функции
@pytest.mark.parametrize('login',test_user_data,indirect=True)
def test_cart(login):
    usera=login
    print('Разные пользователи добавляют корзину %s'%usera)
    assert usera!=''

Process finished with exit code 0
Откройте домашнюю страницу и войдите в систему Линда.
PASSED [ 33%] Разные пользователи добавляют корзину покупок, Линда
Откройте домашнюю страницу и войдите в Sai.
PASSED [ 66%] Разные пользователи добавляют корзину покупок сай
Откройте домашнюю страницу и войдите в Tom
PASSED [100%] Разные пользователи добавляют корзину покупок tom

Параметризация 3

Язык кода:javascript
копировать
import pytest
test_user_data=[
    { 
   'user':'linda','password':'8888'},
    { 
   'user':'servenruby','password':'123456'},
    { 
   'user':'test01','password':''}
]

@pytest.fixture(scope='module')
def login_r(request):
    #Он может быть передан в форме dict. Хотя передается один параметр, эффекта передачи нескольких параметров можно добиться с помощью метода keyiz.
    user=request.param['user']
    pwd=request.param['password']
    print('\nОткройте домашнюю страницу и приготовьтесь войти в систему, войдите в систему, пользователь %s, пароль %s'%(user,pwd))
    if pwd:
        return True
    else:
        return False

#Это драйвер параметров pytest, indirect=True означает выполнение login_r как функции
@pytest.mark.parametrize('login_r',test_user_data,indirect=True)
def test_cart(login_r):
    #Сценарий использования входа в систему
    a=login_r
    print('тестовый вариант использования login_riz, возвращаемое значение %s'%a)
    assert a, «Причина сбоя, пароль пуст»

Откройте домашнюю страницу и приготовьтесь войти в систему, войдите как пользователь linda, пароль 8888.
PASSED [ 33%]тестовый вариант использования, возвращаемое значение login_riz True

Откройте домашнюю страницу и приготовьтесь войти в систему, войдите как пользовательServenRuby, пароль 123456.
PASSED [ 66%]тестовый вариант использования, возвращаемое значение login_riz True

Откройте домашнюю страницу и приготовьтесь войти в систему. Войдите в систему под именем пользователя test01 и паролем.
FAILED [100%]Возвращаемое значение Login_riz False в тестовом варианте использования


бить Откройте домашнюю страницу и приготовьтесь войти в систему, войдите как пользователь linda, пароль 8888.
PASSED [ 33%]тестовый вариант использования, возвращаемое значение login_riz True

Откройте домашнюю страницу и приготовьтесь войти в систему, войдите как пользовательServenRuby, пароль 123456.
PASSED [ 66%]тестовый вариант использования, возвращаемое значение login_riz True

Откройте домашнюю страницу и приготовьтесь войти в систему. Войдите в систему под именем пользователя test01 и паролем.
FAILED [100%]Возвращаемое значение Login_riz False в тестовом варианте использования

test_mark_param_request2.py:19 (test_cart[login_r2])
login_r = False

@pytest.mark.parametrize('login_r',test_user_data,indirect=True)
def test_cart(login_r):
#Сценарий использования входа в систему
a=login_r
print('тестовый вариант использования login_riz, возвращаемое значение %s'%a)
> assert a, «Причина сбоя, пароль пуст»
E AssertionError: Причина сбоя, пароль пуст
E assert False

Параметризация 3*3

Язык кода:javascript
копировать
import pytest
test_user_data1=[{ 
   'user':'linda','password':'888888'},
                 { 
   'user':'servenruby','password':'123456'},
                 { 
   'user':'test01','password':''}]
test_user_data2=[{ 
   'q':'Китай Пинг Ань','count':3,'page':1},
                 { 
   'q':'Alibaba','count':2,'page':2},
                 { 
   'q':'pdd','count':3,'page':1}]
@pytest.fixture(scope='module')
def login_r(request):
    #Это не может принять входной параметр, получить параметр
    user=request.param['user']
    pwd=request.param['password']
    print('\nИмя пользователя: %s, пароль: %s'%(пользователь,пароль))

@pytest.fixture(scope='module')
def query_param(request):
    q=request.param['q']
    count=request.param['count']
    page=request.param['page']
    print('запрос к поисковому слову %s'%q)
    return request.param

#Это основано на pytestизданных, indirect=True выполняет login_r как функцию
#Выполняем снизу вверх
#Два данных объединены в тест, и необходимо выполнить 3*3 варианта использования теста (количество test_user_data1из*количество test_user_data2из
@pytest.mark.parametrize('query_param',test_user_data2,indirect=True)
@pytest.mark.parametrize('login_r',test_user_data1,indirect=True)
def test_login(login_r,query_param):
    #Сценарий использования входа в систему
    print(login_r)
    print(query_param)


pytest_mark_request3.py::test_login[login_r1-query_param0] ✓ 44% ████▌ Запрос из поискового запроса pdd
None
{ 
   'q': 'pdd', 'count': 3, 'page': 1}

pytest_mark_request3.py::test_login[login_r1-query_param2] ✓ 56% █████▋
Имя пользователя: Линда, пароль: 888888
None
{ 
   'q': 'pdd', 'count': 3, 'page': 1}

pytest_mark_request3.py::test_login[login_r0-query_param2] ✓ 67% ██████▋
Имя пользователя: test01, пароль:
None
{ 
   'q': 'pdd', 'count': 3, 'page': 1}

pytest_mark_request3.py::test_login[login_r2-query_param2] ✓ 78% ███████▊ Запрос из поискового запроса Alibaba
None
{ 
   'q': «Алибаба», 'count': 2, 'page': 2}

pytest_mark_request3.py::test_login[login_r2-query_param1] ✓ 89% ████████▉ Запрос из поискового запроса Ping An of China
None
{ 
   'q': «Китайский мир», 'count': 3, 'page': 1}

pytest_mark_request3.py::test_login[login_r2-query_param0] ✓ 100% ██████████

5. Сторонние плагины

1. Настройте порядок выполнения тест-кейсов

Сценарий: естественный порядок выполнения не учитывается или вы хотите изменить порядок выполнения, например добавив Сначала должен быть выполнен вариант использования данных, а затем вариант использования удаления. По умолчанию тестовые случаи указаны по имени. Называется последовательным выполнением. • решать: • Установка: пип install pytest-ordering • Добавьте следующий декоратор в тестовый метод •@pytest.mark.last    —Последняя казнь • @pytest.mark.run(order=1) — какое выполнение По умолчанию pytest выполняется в алфавитном порядке.

Язык кода:javascript
копировать
import pytest
@pytest.mark.run(order=1)
def test_01():
    print('test01')

@pytest.mark.run(order=2)
def test_02():
    print('test01')
@pytest.mark.last
def test_06():
    print('test01')

def test_04():
    print('test01')

def test_05():
    print('test01')
@pytest.mark.run(order=3)
def test_03():
    print('test01')

pytest_order.py::test_01 PASSED [ 16%]test01

pytest_order.py::test_02 PASSED [ 33%]test01

pytest_order.py::test_03 PASSED [ 50%]test01

pytest_order.py::test_04 PASSED [ 66%]test01

pytest_order.py::test_05 PASSED [ 83%]test01

pytest_order.py::test_06 PASSED [100%]test01

2. Выполнение варианта использования прекращается при возникновении ошибки.

• Его можно остановить только после завершения обычного выполнения. Если вы хотите остановить тест при возникновении ошибки: -x Вы также можете прекратить тестирование, когда количество n ошибок вариантов использования достигнет указанного числа: - – maxfail=n • осуществлять: • pytest -x -v -s имя_файла.py      ——- -x останавливается при возникновении ошибки • pytest -x -v -s имя_файла.py —maxfail=2  ——- –maxfail=2 Он останавливается, когда обнаруживает две ошибки.

3. Перезапустите вариант использования после сбоя.

**Сценарий: • Когда тест не пройден и повторяется n раз, добавляется задержка между повторами. время, а затем запустите снова через n секунд. • осуществлять: • Установка: пип install pytest-rerunfailures • pytest -v – -reruns 5 –reruns-delay 1 —Подождите 1 секунду каждый раз Повторить попытку 5 раз

4. Несколько утверждений по-прежнему будут выполняться после сообщения об ошибке спереди.

pip3 install pytest-assume продолжает выполнение после подтверждения, но необходимо изменить утверждение**

Язык кода:javascript
копировать
@pytest.mark.parametrize(('x', 'y'), [(1, 1), (1, 0), (0, 1)])
def test_assume(x, y):
    pytest.assume(x == y)
    pytest.assume(3 == 4)
    pytest.assume(5 == 9)

5. Многопоточное параллельное и распределенное выполнение.

Сценарий: 1000 тестовых примеров, выполнение одного тестового примера занимает 1 минуту, выполнение одного тестировщика занимает 1000 минут. колокол. Обычно мы обмениваем затраты на рабочую силу на затраты времени. Если мы добавим несколько человек для совместной работы, время сократится. короткий. Если 10 людям потребуется всего 100 минут, чтобы выполнить его вместе, это параллельное тестирование и распределенный сценарий. решить: плагин распределенного выполнения pytest: pytest-xdist, выполнение на нескольких процессорах или хостах Предпосылка: все варианты использования независимы и не имеют последовательности. Они могут выполняться случайным образом и повторяться. Влияние на другие варианты использования. Установка:Pip3 install pytest-xdist • Несколько процессоров выполняют вариант использования параллельно, напрямую добавьте -n 3 — количество параллелизма: pytest -n 3 • Выполнять вместе под несколькими терминалами

Язык кода:javascript
копировать
import pytest
import time

@pytest.mark.parametrize('x',list(range(10)))
def test_somethins(x):
    time.sleep(1)

pytest -v -s -n 5 test_xsdist.py  ----Выполнять 5 за раз

Запустите следующий код, структура проекта следующая.

web_conf_py — имя проекта.

Язык кода:javascript
копировать
│  conftest.py
│  __init__.py
│              
├─baidu
│  │  conftest.py
│  │  test_1_baidu.py
│  │  test_2.py
│  │  __init__.py 
│          
├─blog
│  │  conftest.py
│  │  test_2_blog.py
│  │  __init__.py  

Ссылка на код:

Язык кода:javascript
копировать
# web_conf_py/conftest.py
import pytest

@pytest.fixture(scope="session")
def start():
    print("\nОткрыть домашнюю страницу")
    return "yoyo"

# web_conf_py/baidu/conftest.py
import pytest

@pytest.fixture(scope="session")
def open_baidu():
    print("Откройте страницу Baidu_session")

# web_conf_py/baidu/test_1_baidu.py
import pytest
import time

def test_01(start, open_baidu):
    print("тестовый вариант использования test_01")
    time.sleep(1)
    assert start == "yoyo"

def test_02(start, open_baidu):
    print("тестовый вариант использования test_02")
    time.sleep(1)
    assert start == "yoyo"

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


# web_conf_py/baidu/test_2.py
import pytest
import time

def test_06(start, open_baidu):
    print("тестовый вариант использования test_01")
    time.sleep(1)
    assert start == "yoyo"
def test_07(start, open_baidu):
    print("тестовый вариант использования test_02")
    time.sleep(1)
    assert start == "yoyo"

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


# web_conf_py/blog/conftest.py
import pytest

@pytest.fixture(scope="function")
def open_blog():
    print("Открыть страницу_функции блога")

# web_conf_py/blog/test_2_blog.py

import pytest
import time
def test_03(start, open_blog):
    print("тестовый вариант использования test_03")
    time.sleep(1)
    assert start == "yoyo"

def test_04(start, open_blog):
    print("тестовый вариант использования test_04")
    time.sleep(1)
    assert start == "yoyo"

def test_05(start, open_blog):
    '''Вызов модуля Baidu из-за кросс-модуля из конфликта'''
    print("тестовый вариант использования test_05, вызов Baidu между модулями")
    time.sleep(1)
    assert start == "yoyo"

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

Нормальная работа занимает время: 7,12 секунды.

Язык кода:javascript
копировать
E:\YOYO\web_conf_py>pytest
============================= test session starts =============================
platform win32 -- Python 3.6.0, pytest-3.6.3, py-1.5.4, pluggy-0.6.0
rootdir: E:\YOYO\web_conf_py, inifile:
plugins: xdist-1.23.2, metadata-1.7.0, html-1.19.0, forked-0.2
collected 7 items

baidu\test_1_baidu.py ..                                                 [ 28%]
baidu\test_2.py ..                                                       [ 57%]
blog\test_2_blog.py ...                                                  [100%]

========================== 7 passed in 7.12 seconds ===========================

Установите количество параллельных запусков равным 3, а затраченное время — 3,64 секунды, что значительно сокращает время варианта использования.

Язык кода:javascript
копировать
E:\YOYO\web_conf_py>pytest -n 3
============================= test session starts =============================
platform win32 -- Python 3.6.0, pytest-3.6.3, py-1.5.4, pluggy-0.6.0
rootdir: E:\YOYO\web_conf_py, inifile:
plugins: xdist-1.23.2, metadata-1.7.0, html-1.19.0, forked-0.2
gw0 [7] / gw1 [7] / gw2 [7]
scheduling tests via LoadScheduling
.......                                                                  [100%]
========================== 7 passed in 3.64 seconds ===========================

6. Другие интересные плагины

Я не буду здесь вдаваться в подробности. Если вам это нравится, вы можете изучить это самостоятельно.

7. Используйте pytest для выполнения тестовых случаев unittest.

Выполнение unitest происходит так же, как и раньше. Старайтесь не смешивать и использовать какие-то причудливые варианты. Просто используйте тот, который вам нравится. Я не буду здесь вдаваться в подробности.

8. pytest-html генерирует отчеты

pytest-HTML — это плагин, используемый pytest для создания HTML-отчетов о результатах тестирования. Совместимость с Python 2.7,3.6.

pytest-html 1. Адрес исходного кода на github [https://github.com/pytest-dev/pytest-html]

2.pip-установка

Язык кода:javascript
копировать
$ pip install pytest-html

3.Метод выполнения

Язык кода:javascript
копировать
$ pytest --html=report.html

HTML-отчет 1. Откройте cmd, перейдите в каталог, в котором вам нужно выполнить тестовый пример pytest, и выполните команду: pytest –html=report.html

2. После выполнения в текущем каталоге будет создан файл отчета report.html, эффект отображения будет следующим:

Укажите путь к отчету 1. Отчет, созданный путем прямого выполнения «pytest –html=report.html», будет находиться по тому же пути, что и текущий скрипт. Если вы хотите указать место хранения отчета, поместите его в папку отчета в том же каталоге. текущего сценария.

Язык кода:javascript
копировать
pytest --html=./report/report.html

2. Если вы хотите указать вариант использования для выполнения определенного файла .py и всех вариантов использования в определенной папке, вам необходимо добавить параметр. Конкретные правила можно найти в [pytest document 2 — правила выполнения вариантов использования]

Отчеты отображаются независимо 1. CSS отчета, созданного указанным выше методом, независим. Стиль будет потерян при совместном использовании отчета. Чтобы лучше делиться отчетом и отображать его по электронной почте, вы можете объединить стиль CSS в HTML.

Язык кода:javascript
копировать
$ pytest --html=report.html --self-contained-html

Показать параметры По умолчанию все строки в таблице «Результаты» будут развернуты, кроме строк с «Пройдено тестов».

Это поведение можно настроить с помощью параметра запроса: ?collapsed=Passed,XFailed,Skipped.

Дополнительные возможности 1. Дополнительные функции можно найти в официальной документации [https://github.com/pytest-dev/pytest-html].

6. Управление журналами и покрытие кода

1. Применение логирования в pytest

2. Значение логов и уровней

Информация об отладке автоматических тестовых случаев очень полезна. Она позволяет нам узнать текущий статус выполнения, какой этап выполнения, соответствующую информацию об ошибках и т. д. Иногда ее можно найти в pytest. Иногда выводится не вся информация, например информация о проходе. test по умолчанию. Вариант использования не имеет вывода на печать. В этой статье рассказывается, как отображать всю информацию журнала в реальном времени в pytest.

1. Используйте печать для вывода информации журнала slowTest_print.py

Язык кода:javascript
копировать
import time
 
def test_1():
    print 'test_1'
    time.sleep(1)
    print 'after 1 sec'
    time.sleep(1)
    print 'after 2 sec'
    time.sleep(1)
    print 'after 3 sec'
    assert 1, 'should pass'
 
def test_2():
    print 'in test_2'
    time.sleep(1)
    print 'after 1 sec'
    time.sleep(1)
    print 'after 2 sec'
    time.sleep(1)
    print 'after 3 sec'
    assert 0, 'failing for demo purposes'

Когда вы запускаете вышеуказанную программу, pytest захватывает весь вывод, сохраняет его до тех пор, пока не будут выполнены все тестовые примеры, и выводит только информацию о неудачных тестовых случаях. Для успешных тестовых случаев информация для печати не отображается. Судя по результатам работы, приведенным ниже, если вам нужно проверить статус выполнения test_1(), информация журнала не отображается, и печать не отображается.

Язык кода:javascript
копировать
C:\Users\yatyang\PycharmProjects\pytest_example>pytest -v slowTest_print.py
============================= test session starts =============================
platform win32 -- Python 2.7.13, pytest-3.0.6, py-1.4.32, pluggy-0.4.0 -- C:\Python27\python.exe
cachedir: .cache
metadata: { 
   'Python': '2.7.13', 'Platform': 'Windows-7-6.1.7601-SP1', 'Packages': { 
   'py': '1.4.32', 'pytest': '3.0.6', 'pluggy': '0.4.0'}, 'JAVA_HOME': 'C:\\Program Files (x86)\\Java\\jd
k1.7.0_01', 'Plugins': {'html': '1.14.2', 'metadata': '1.3.0'}}
rootdir: C:\Users\yatyang\PycharmProjects\pytest_example, inifile:
plugins: metadata-1.3.0, html-1.14.2
collected 2 items 

slowTest_print.py::test_1 PASSED
slowTest_print.py::test_2 FAILED

================================== FAILURES ===================================
___________________________________ test_2 ____________________________________

    def test_2():
        print 'in test_2'
        time.sleep(1)
        print 'after 1 sec'
        time.sleep(1)
        print 'after 2 sec'
        time.sleep(1)
        print 'after 3 sec'
>       assert 0, 'failing for demo purposes'
E       AssertionError: failing for demo purposes
E       assert 0

slowTest_print.py:22: AssertionError
---------------------------- Captured stdout call -----------------------------
in test_2
after 1 sec
after 2 sec
after 3 sec
===================== 1 failed, 1 passed in 6.45 seconds ======================

C:\Users\yatyang\PycharmProjects\pytest_example>

мы можем использовать‘-s’параметрили «-capture=no», чтобы можно было вывести всю информацию о тестовой печати. Однако pytest по-прежнему будет ждать выполнения всех тестовых случаев, прежде чем отображать результаты. Вы можете видеть, что test_1 ниже также отображает информацию, связанную с печатью.

Язык кода:javascript
копировать
C:\Users\yatyang\PycharmProjects\pytest_example>py.test --capture=no slowTest_print.py
============================= test session starts =============================
platform win32 -- Python 2.7.13, pytest-3.0.6, py-1.4.32, pluggy-0.4.0
metadata: { 
   'Python': '2.7.13', 'Platform': 'Windows-7-6.1.7601-SP1', 'Packages': { 
   'py': '1.4.32', 'pytest': '3.0.6', 'pluggy': '0.4.0'}, 'JAVA_HOME': 'C:\\Program Files (x86)\\Java\\jd
k1.7.0_01', 'Plugins': {'html': '1.14.2', 'metadata': '1.3.0'}}
rootdir: C:\Users\yatyang\PycharmProjects\pytest_example, inifile:
plugins: metadata-1.3.0, html-1.14.2
collected 2 items 

slowTest_print.py test_1
after 1 sec
after 2 sec
after 3 sec
.in test_2
after 1 sec
after 2 sec
after 3 sec
F

================================== FAILURES ===================================
___________________________________ test_2 ____________________________________

    def test_2():
        print 'in test_2'
        time.sleep(1)
        print 'after 1 sec'
        time.sleep(1)
        print 'after 2 sec'
        time.sleep(1)
        print 'after 3 sec'
>       assert 0, 'failing for demo purposes'
E       AssertionError: failing for demo purposes
E       assert 0

slowTest_print.py:22: AssertionError
===================== 1 failed, 1 passed in 6.17 seconds ======================

2. Python Использование журнала В обычных обстоятельствах во время процесса отладки некоторых программ мы позволяем ему выводить некоторую информацию, особенно в некоторых крупных программах. Мы можем использовать эту информацию, чтобы понять состояние работы программы. Python предоставляет модуль журналирования, который может записывать то, что мы делаем. Хочу Вся информация сохраняется в файле журнала для удобного просмотра.

Язык кода:javascript
копировать
import logging

logging.debug('This is debug message')
logging.info('This is info message')
logging.warning('This is warning message')

Печать на экране: WARNING:root:This is warning message По умолчанию при ведении журнала журналы выводятся на экран, уровень журнала — ПРЕДУПРЕЖДЕНИЕ; Взаимосвязь между уровнем журнала и его размером: КРИТИЧЕСКАЯ. > ERROR > WARNING > INFO > DEBUG > NOTSET, конечно, вы также можете определить уровень журнала самостоятельно.

3. Используйте ведение журнала вместо печати в pytest Давайте теперь посмотрим на разницу между использованием вывода журнала вместо вывода на печать в тестовом примере pytest. slowTest_logging.py

Язык кода:javascript
копировать
import time
import logging

logging.basicConfig(level=logging.DEBUG)

def test_1():
    log = logging.getLogger('test_1')
    time.sleep(1)
    log.debug('after 1 sec')
    time.sleep(1)
    log.debug('after 2 sec')
    time.sleep(1)
    log.debug('after 3 sec')
    assert 1, 'should pass'


def test_2():
    log = logging.getLogger('test_2')
    time.sleep(1)
    log.debug('after 1 sec')
    time.sleep(1)
    log.debug('after 2 sec')
    time.sleep(1)
    log.debug('after 3 sec')
    assert 0, 'failing for demo purposes'

Результаты работы следующие: Является ли отображение информации журнала более читабельным? Однако pytest все равно приходится ждать, пока все результаты будут завершены, прежде чем они будут полностью выведены на экран, и нет возможности увидеть статус работы в реальном времени. Например, если мы хотим протестировать новое изображение сейчас, мы не знаем, насколько хорошее качество. Если тестовых случаев много, тестировщику придется подождать. Возможно, выполнение можно остановить, если некоторые из них. предыдущие тесты провалились. Так как же добиться отображения в реальном времени? Пожалуйста, смотрите метод 4.

Язык кода:javascript
копировать
C:\Users\yatyang\PycharmProjects\pytest_example>pytest slowTest_logging.py
============================= test session starts =============================
platform win32 -- Python 2.7.13, pytest-3.0.6, py-1.4.32, pluggy-0.4.0
metadata: { 
   'Python': '2.7.13', 'Platform': 'Windows-7-6.1.7601-SP1', 'Packages': { 
   'py': '1.4.32', 'pytest': '3.0.6', 'pluggy': '0.4.0'}, 'JAVA_HOME': 'C:\\Program Files (x86)\\Java\\jd
k1.7.0_01', 'Plugins': {'html': '1.14.2', 'metadata': '1.3.0'}}
rootdir: C:\Users\yatyang\PycharmProjects\pytest_example, inifile:
plugins: metadata-1.3.0, html-1.14.2
collected 2 items 

slowTest_logging.py .F

================================== FAILURES ===================================
___________________________________ test_2 ____________________________________

    def test_2():
        log = logging.getLogger('test_2')
        time.sleep(1)
        log.debug('after 1 sec')
        time.sleep(1)
        log.debug('after 2 sec')
        time.sleep(1)
        log.debug('after 3 sec')
>       assert 0, 'failing for demo purposes'
E       AssertionError: failing for demo purposes
E       assert 0

slowTest_logging.py:25: AssertionError
---------------------------- Captured stderr call -----------------------------
DEBUG:test_2:after 1 sec
DEBUG:test_2:after 2 sec
DEBUG:test_2:after 3 sec
===================== 1 failed, 1 passed in 6.37 seconds ======================
Язык кода:javascript
копировать
C:\Users\yatyang\PycharmProjects\pytest_example>pytest -s slowTest_logging.py
============================= test session starts =============================
platform win32 -- Python 2.7.13, pytest-3.0.6, py-1.4.32, pluggy-0.4.0
metadata: { 
   'Python': '2.7.13', 'Platform': 'Windows-7-6.1.7601-SP1', 'Packages': { 
   'py': '1.4.32', 'pytest': '3.0.6', 'pluggy': '0.4.0'}, 'JAVA_HOME': 'C:\\Program Files (x86)\\Java\\jd
k1.7.0_01', 'Plugins': {'html': '1.14.2', 'metadata': '1.3.0'}}
rootdir: C:\Users\yatyang\PycharmProjects\pytest_example, inifile:
plugins: metadata-1.3.0, html-1.14.2
collected 2 items 

slowTest_logging.py DEBUG:test_1:after 1 sec
DEBUG:test_1:after 2 sec
DEBUG:test_1:after 3 sec
.DEBUG:test_2:after 1 sec
DEBUG:test_2:after 2 sec
DEBUG:test_2:after 3 sec
F

================================== FAILURES ===================================
___________________________________ test_2 ____________________________________

    def test_2():
        log = logging.getLogger('test_2')
        time.sleep(1)
        log.debug('after 1 sec')
        time.sleep(1)
        log.debug('after 2 sec')
        time.sleep(1)
        log.debug('after 3 sec')
>       assert 0, 'failing for demo purposes'
E       AssertionError: failing for demo purposes
E       assert 0

slowTest_logging.py:25: AssertionError
===================== 1 failed, 1 passed in 6.18 seconds ======================

4. pytest использует ведение журнала и –capture=no для вывода информации журнала в режиме реального времени. Пожалуйста, запустите следующую программу самостоятельно. Вы можете видеть, что программа выводит статус выполнения текущего тестового примера в режиме реального времени.

Язык кода:javascript
копировать
C:\Users\yatyang\PycharmProjects\pytest_example>pytest -s slowTest_logging.py
============================= test session starts =============================
platform win32 -- Python 2.7.13, pytest-3.0.6, py-1.4.32, pluggy-0.4.0
metadata: { 
   'Python': '2.7.13', 'Platform': 'Windows-7-6.1.7601-SP1', 'Packages': { 
   'py': '1.4.32', 'pytest': '3.0.6', 'pluggy': '0.4.0'}, 'JAVA_HOME': 'C:\\Program Files (x86)\\Java\\jd
k1.7.0_01', 'Plugins': {'html': '1.14.2', 'metadata': '1.3.0'}}
rootdir: C:\Users\yatyang\PycharmProjects\pytest_example, inifile:
plugins: metadata-1.3.0, html-1.14.2
collected 2 items 

slowTest_logging.py DEBUG:test_1:after 1 sec
DEBUG:test_1:after 2 sec
DEBUG:test_1:after 3 sec
.DEBUG:test_2:after 1 sec
DEBUG:test_2:after 2 sec
DEBUG:test_2:after 3 sec
F

================================== FAILURES ===================================
___________________________________ test_2 ____________________________________

    def test_2():
        log = logging.getLogger('test_2')
        time.sleep(1)
        log.debug('after 1 sec')
        time.sleep(1)
        log.debug('after 2 sec')
        time.sleep(1)
        log.debug('after 3 sec')
>       assert 0, 'failing for demo purposes'
E       AssertionError: failing for demo purposes
E       assert 0

slowTest_logging.py:25: AssertionError
===================== 1 failed, 1 passed in 6.20 seconds ======================

5. Резюме При написании автоматизированных тестовых случаев очень важно добавлять полезную информацию журнала. Например, во время первоначального процесса отладки можно получить точную информацию об отладке, если в работе возникнет проблема. Позже, во время стабильной работы, другим тестировщикам будет легко его запустить, поэтому каждый должен обратить внимание на отладочную информацию тестового примера. Из этой статьи вы узнаете, как использовать pytest, logging и –capture=no для вывода всей информации журнала в режиме реального времени при запуске тестовых случаев.

3. Покрытие кода — в основном используется при модульном тестировании.

1. Часть 1 (—- pytest-cov) Введение: pytest-cov Это плагин pytest, и его суть тоже справочная. python coverage Библиотека Используется для подсчета покрытия кода. Следующая статья предназначена только для понимания. В реальных проектах мы все используем API для вызова интерфейса, поэтому использование реальных проектов будет более сложным. Это будет объяснено в следующий раз.

Дополнительно: покрытие Причина в том, что освещение является разновидностью покрытия утверждений. Оно не может интерпретировать вашу логику. Если оно действительно имеет смысл, его необходимо объединить с самим проектом. Эти данные о покрытии не очень убедительны, поэтому не следуйте им вслепую. Вообще говоря: покрытие пути > Охват решений > покрытие заявлений

Установить

Язык кода:javascript
копировать
pip install pytest-cover

Установить После окончания там

Язык кода:javascript
копировать
py.test -h можно увидеть имеет следующее использование,иллюстрировать Установитьуспех:

coverage reporting with distributed testing support:

пример Создайте три новых файла: cau.py и test_conver.py в том же коде каталога. Файл run.py находится в каталоге верхнего уровня pp. Взаимосвязь кода следующая.

1. Создайте новый файл функции cau.py.

Язык кода:javascript
копировать
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def cau (type,n1, n2):

    if type==1:
        a=n1 + n2
    elif type==2:
        a = n1 - n2
    else:
        a=n1 * n2
    return a

2. Создайте новый тестовый файл test_conver.py:

Язык кода:javascript
копировать
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from code.cau import cau
class Test_cover:
    def test_add(self):
        a=cau(1,2,3)
        assert a==3

3. Создайте новый скрипт выполнения run.py.

Язык кода:javascript
копировать
#!/usr/bin/env ```python
# -*- coding: utf-8 -*-
import pytest

if __name__=='__main__':
	pytest.main(["--cov=./code/" ,"--cov-report=html","--cov-config=./code/.coveragerc"] )  # Выполнить дело в определенном каталоге

иллюстрировать:–covпараметр Далее следует тестовый каталог. (После тестирования конкретный файл указать нельзя.) Программный код и тестовый скрипт должны находиться в одном файле. –cov-report=html Создать отчет , требуется только Python run.py Просто запусти это

Язык кода:javascript
копировать
coveragerc  Означает пропуск определенных скриптов из теста покрытия. Файл test_cover.py и файл инициализации здесь пропускаются.

Содержание следующее:

Язык кода:javascript
копировать
[run]
omit =
	tests/*
	 */__init__.py
	*/test_cover.py

результат После генерации вы можете напрямую щелкнуть indexhtml.

Вы можете увидеть следующий статус выполнения: Зеленый означает выполнение, красный — не выполнение. Проверьте логику кода самостоятельно и сделайте вывод, что результат верен.

Вторая: Следующая глава (— coverage.py api) Использование pytest-cov Невозможно использовать для статистики Охват тестовых сценариев для служб вызовов API покрыт, но большинство проектов в основном используют вызовы API. Поэтому нам дополнительно нужно использовать Cover.py api Давайте посчитаем. Когда вы устанавливаете Pytest-cov, значение «Установить покрытие» уже установлено по умолчанию. Это Библиотека.

Запуск службы Чтобы сканировать код, при запуске службы необходимо вставить конфигурацию, связанную с покрытием. Я запустил flask здесь, поэтому добавил его в код запуска flask следующим образом:

Язык кода:javascript
копировать
if __name__ == '__main__':
    cov = Coverage()
    cov.start()  # Начать инструментирование кода
    print ("qidong")
    app.run(debug=True, host='0.0.0.0',port=9098)  #Изначально была только эта строка
    cov.stop()  # Остановить запись
    print ("guanbi")
    cov.save()  # Сохранить в .coverage середина
    print ("save")
    cov.html_report()  # генерировать HTML Отчет

Изначально мы запускали python xx.py вот так, но сейчас это невозможно. Его необходимо изменить на следующее: источник представляет каталог, а xx представляет исполняемый файл.

Язык кода:javascript
копировать
coverage run --source='/xxx/' xx.py    

Схема работы запуска следующая:

Затем вызовите свой сценарий автоматизации (сценарий автоматизации напрямую вызывает API, предоставляемый службой).

Если автоматизация работает нормально, вы можете увидеть запущенные запросы.

Вышеупомянутое показывает, что с вашим скриптом и сервисом проблем нет.

После того, как ctr-c останавливает сценарий, наконец отображается сохранение. Если отображается сообщение «Предупреждение Coverage.py: данные не собраны. (данные не собраны)», значит, возникла проблема с работой службы. служба не работает с вашим кодом.

Генерация отчета Введите следующую команду

Язык кода:javascript
копировать
coverage report

Введите последний шаг на последнем шаге

Язык кода:javascript
копировать
coverage html

Это сохраняет html-файлы.

Чтобы просмотреть экспорт в окне, нажмите на конкретный файл и нажмите «Выполнить». Вы увидите, что зеленый файл запущен. Но проблема в том, что вы обнаружите, что какой-то код должен быть выполнен, но не выполняется. Поэтому сложно сказать, точны ли данные о покрытии.

4. Система отчетов о тестировании Allure

Pytest+allure теперь объединен с jenkins. Я считаю, что это может сделать каждый. Если вы этого не знаете, вы можете посмотреть другой мой блог о непрерывной интеграции.

5. Индивидуальные отчеты

Индивидуальные отчеты Особенность: Отметьте основные функциональные модули История: Отметьте функции ветвления в функциональном модуле «Функции». Серьезность: отметьте уровень важности тестового примера. Шаг: важные шаги по маркировке тестовых примеров Проблема и TestCase: отметьте «Проблему» и «Случай» и добавьте URL-адрес.

1. Подробное объяснение настройки функций.

Язык кода:javascript
копировать
# -*- coding: utf-8 -*-
# @Time : 2018/8/17 10:10 утра
# @Author : WangJuan
# @File : test_case.py
import allure
import pytest


@allure.feature('test_module_01')
def test_case_01():
    """ Описание варианта использования: Тест case 01 """
    assert 0
    
@allure.feature('test_module_02')
def test_case_02():
    """ Описание варианта использования: Тест case 02 """
    assert 0 == 0
    
    
if __name__ == '__main__':
    pytest.main(['-s', '-q', '--alluredir', './report/xml'])

Добавьте функцию, и отображение отчета показано на рисунке ниже.

2. Подробное объяснение настройки истории.

Язык кода:javascript
копировать
# -*- coding: utf-8 -*-
# @Time : 2018/8/17 10:10 утра
# @Author : WangJuan
# @File : test_case.py
import allure
import pytest


@allure.feature('test_module_01')
@allure.story('test_story_01')
def test_case_01():
    """ Описание варианта использования: Тест case 01 """
    assert 0

@allure.feature('test_module_01')
@allure.story('test_story_02')
def test_case_02():
    """ Описание варианта использования: Тест case 02 """
    assert 0 == 0


if __name__ == '__main__':
    pytest.main(['-s', '-q', '--alluredir', './report/xml'])

Добавьте историю, и отображение отчета показано на рисунке ниже.

3. Подробное объяснение названия варианта использования и настройки описания варианта использования.

Язык кода:javascript
копировать
# -*- coding: utf-8 -*-
# @Time : 2018/8/17 10:10 утра
# @Author : WangJuan
# @File : test_case.py
import allure
import pytest

@allure.feature('test_module_01')
@allure.story('test_story_01')
#test_case_01 — заголовок варианта использования.
def test_case_01():
    """ Описание варианта использования. Это описание варианта использования. Тест. case 01. Опиши себя """
    #Комментарии – это описания вариантов использования.
    assert 0

if __name__ == '__main__':
    pytest.main(['-s', '-q', '--alluredir', './report/xml'])

Добавьте заголовок варианта использования и описание варианта использования. Экран отчета показан на рисунке ниже.

4 Подробное объяснение настройки серьезности Определение уровня серьезности в Allure: 1、 Уровень блокировки: Дефект прерывания (клиентская программа не отвечает и не может выполнить следующий шаг) 2、 Критический уровень: критический дефект ( Функциональная точка отсутствует) 3、 Нормальный уровень: Обычные дефекты (ошибки численного расчета). 4、 Незначительный уровень: незначительный дефект (ошибка интерфейса не соответствует требованиям пользовательского интерфейса) 5、 Тривиальный уровень: незначительные дефекты (нет запроса на ввод необходимых элементов или запрос неправильный).

Язык кода:javascript
копировать
# -*- coding: utf-8 -*-
# @Time : 2018/8/17 10:10 утра
# @Author : WangJuan
# @File : test_case.py
import allure
import pytest


@allure.feature('test_module_01')
@allure.story('test_story_01')
@allure.severity('blocker')
def test_case_01():
    """ Описание варианта использования: Тест case 01 """
    assert 0

@allure.feature('test_module_01')
@allure.story('test_story_01')
@allure.severity('critical')
def test_case_02():
    """ Описание варианта использования: Тест case 02 """
    assert 0 == 0

@allure.feature('test_module_01')
@allure.story('test_story_02')
@allure.severity('normal')
def test_case_03():
    """ Описание варианта использования: Тест case 03 """
    assert 0

@allure.feature('test_module_01')
@allure.story('test_story_02')
@allure.severity('minor')
def test_case_04():
    """ Описание варианта использования: Тест case 04 """
    assert 0 == 0

    
if __name__ == '__main__':
    pytest.main(['-s', '-q', '--alluredir', './report/xml'])

Добавьте уровень серьезности, и окно отчета показано на рисунке ниже.

5. Подробное объяснение настройки шага.

Язык кода:javascript
копировать
# -*- coding: utf-8 -*-
# @Time : 2018/8/17 10:10 утра
# @Author : WangJuan
# @File : test_case.py
import allure
import pytest

@allure.step("Добавьте строки: {0}, {1}")     
# шаге теста можно автоматически получить параметр функции через форматмеханизм
def str_add(str1, str2):
    if not isinstance(str1, str):
        return "%s is not a string" % str1
    if not isinstance(str2, str):
        return "%s is not a string" % str2
    return str1 + str2

@allure.feature('test_module_01')
@allure.story('test_story_01')
@allure.severity('blocker')
def test_case():
    str1 = 'hello'
    str2 = 'world'
    assert str_add(str1, str2) == 'helloworld'


if __name__ == '__main__':
    pytest.main(['-s', '-q', '--alluredir', './report/xml'])

Добавьте отображение шагов и отчетов, как показано ниже.

6. Подробное объяснение настройки проблемы и TestCase.

Язык кода:javascript
копировать
# -*- coding: utf-8 -*-
# @Time : 2018/8/17 10:10 утра
# @Author : WangJuan
# @File : test_case.py
import allure
import pytest


@allure.step("Добавьте строки: {0}, {1}")     # шаге теста можно автоматически получить параметр функции через форматмеханизм
def str_add(str1, str2):
    print('hello')
    if not isinstance(str1, str):
        return "%s is not a string" % str1
    if not isinstance(str2, str):
        return "%s is not a string" % str2
    return str1 + str2

@allure.feature('test_module_01')
@allure.story('test_story_01')
@allure.severity('blocker')
@allure.issue("http://www.baidu.com")
@allure.testcase("http://www.testlink.com")
def test_case():
    str1 = 'hello'
    str2 = 'world'
    assert str_add(str1, str2) == 'helloworld'


if __name__ == '__main__':
    pytest.main(['-s', '-q', '--alluredir', './report/xml'])

Добавьте Issue и TestCase, и отображение отчета показано на рисунке ниже.

8. Подробное объяснение настройки прикрепления.

Язык кода:javascript
копировать
 file = open('../test.png', 'rb').read()
 allure.attach('test_img', file, allure.attach_type.PNG)

Добавьте в отчет вложения: allure.attach('arg1','arg2','arg3'): arg1: имя вложения, отображаемого в отчете. arg2: указывает содержимое добавленных вложений. arg3: указывает добавленный тип (поддерживается: HTML, JPG, PNG, JSON, OTHER, TEXTXML).

Добавьте параметр AttachParameter, и отображение отчета показано на рисунке ниже.

6. pytest запускает указанный вариант использования

С увеличением функций программного обеспечения появляется все больше и больше модулей, что также означает все больше и больше вариантов использования. Чтобы сэкономить время выполнения и быстро получить отчеты и результаты испытаний, вы можете быстро выполнить варианты использования, запустив указанные варианты использования на работе. .

Пример каталога

spec_sub1_modul_test.py

Язык кода:javascript
копировать
#coding: UTF-8
import pytest

def test_004_spec():
    assert 1==1
def test_005_spec():
    assert True==False
    
class Test_Class():
    def test_006_spec(self):
        assert 'G' in "Goods"

spec_sub2_modul_test.py

Язык кода:javascript
копировать
#coding: UTF-8
import pytest

def test_007_spec():
    assert 1==1
def test_008_spec():
    assert True==False
    
class Test_Class():
    def test_009_spec(self):
        assert 'G' in "Goods"

spec_001_modul_test

Язык кода:javascript
копировать
#coding: UTF-8
import pytest

def test_001_spec():
    assert 1==1
def test_002_spec():
    assert True==False
    
class Test_Class():
    def test_003_spec(self):
        assert 'H' in "Hell,Jerry"

Запустить указанный модуль

Язык кода:javascript
копировать
if __name__ == '__main__':
    pytest.main("-v -s spec_001_modul_test.py")

Запуск пакетных папок (запуск всех вариантов использования в текущей папке, включая подпапки)

Язык кода:javascript
копировать
#coding: UTF-8
import pytest
if __name__ == '__main__':
    pytest.main("-v -s ./")

Запустите указанную папку (все варианты использования в каталоге subpath1)

Язык кода:javascript
копировать
#coding: UTF-8
import pytest
if __name__ == '__main__':
    pytest.main("-v -s subpath1/")

Запустите указанный вариант использования в модуле (вариант использования test_001_spec в работающем модуле)

Язык кода:javascript
копировать
if __name__ == '__main__':
    pytest.main("-v -s spec_001_modul_test.py::test_001_spec")

Запустите вариант использования, указанный в классе (запустите метод test_003_spec класса Test_Class в модуле)

Язык кода:javascript
копировать
if __name__ == '__main__':
   pytest.main("-v -s spec_001_modul_test.py::Test_Class::test_003_spec")

Случай нечеткого соответствия (соответствует текущему каталогу, указанному ниже)

Язык кода:javascript
копировать
if __name__ == '__main__':
    #бегатьspec_001_modul_testмодульсерединавариант использованияимя содержитspecизвариант использования
    pytest.main("-v -s -k spec spec_001_modul_test.py")
    #Запускаем текущую папку, соответствующую варианту использования Test_Classиз, файл класса под вариантом использования
    pytest.main('-s -v -k Test_Class')

7. Провести определенный набор тестов по уровню важности.

Эта отметка используется для определения уровня тестовых примеров или тестовых классов, которые разделены на пять уровней: блокирующий, критический, нормальный, второстепенный и тривиальный. Отметим тестовые сценарии по уровням и просмотрим отчет о тестировании.

8. Добавьте подробное описание теста @allure.description;@allure.title;

1. название дела, заголовок

Вы можете настроить заголовок варианта использования, который по умолчанию соответствует имени функции.

@allure.title

Язык кода:javascript
копировать
# -*- coding: utf-8 -*-
# @Time : 2019/3/12 11:46
# @Author : zzt

import allure
import pytest


@allure.title("Заголовок варианта использования 0")
def test_0():
    pass

@allure.title("Заголовок варианта использования 1")
def test_1():
    pass


def test_2():
    pass

Эффект исполнения:

  1. иллюстрировать

Можно добавить подробные описания теста, чтобы предоставить читателю отчета столько контекста, сколько необходимо.

Два способа: @allure.description предоставляет декоратор, описывающий строку.

@allure.description_html предоставляет некоторый HTML-код в части описания тестового примера (будет изучен).

Язык кода:javascript
копировать
# -*- coding: utf-8 -*-
# @Time : 2019/3/12 11:46
# @Author : zzt

import allure
import pytest

@allure.title("Заголовок варианта использования 0")
@allure.description("Вот некоторые подробности о примере использования test_0, иллюстрировать")
def test_0():
    pass

@allure.title("Заголовок варианта использования 1")
def test_1():
    pass

@allure.title("Заголовок варианта использования 2")
def test_2():
    pass

9. ссылка @allure.link @allure.issue @allure.testcase

@allure.link @allure.issue @allure.testcase

Язык кода:javascript
копировать
# -*- coding: utf-8 -*-
# @Time : 2019/3/12 11:46
# @Author : zzt

import allure
import pytest

@allure.feature('Это метка первого уровня')
class TestAllure():

    @allure.title("Заголовок варианта использования 0")
    @allure.story("Это первый второстепенный тег")
    @pytest.mark.parametrize('param', ['бронза', 'серебро', 'золото'])
    def test_0(self, param):
        allure.attach('Содержимое вложения: '+param, «Я — имя вложения», allure.attachment_type.TEXT)

    @allure.title("Заголовок варианта использования 1")
    @allure.story("Это второй дополнительный тег")
    def test_1(self):
        allure.attach.file(r'E:\Myproject\pytest-allure\test\test_1.jpg', 'Я - имя на прикрепленном скриншоте', attachment_type=allure.attachment_type.JPG)

    @allure.title("Заголовок варианта использования 2")
    @allure.story("Это третий дополнительный тег")
    @allure.issue('http://baidu.com', name='Нажмите на меня, чтобы перейти в Baidu')
    @allure.testcase('http://bug.com/user-login-Lw==.html', name='Нажмите на меня, чтобы перейти на путь Дзен')
    def test_2(self):
        pass

Результат выполненияследующее:

7. Модульное автоматизированное тестирование. В тесте для автоматического выполнения применяются pytest и allure.

1. Отображение отчета о тестировании модуля.

2. Напишите драйвер в conftest, определите область действия сеанса и используйте addfinalizer, чтобы закрыть браузер после теста.

3. Внешнее автоматизированное тестирование. Практическая демонстрация функции поиска Baidu.

Отчеты могут отображать множество различных типов вложений, дополняющих тесты, шаги и т. д.

allure.attach(body, name, attachment_type, extension)

body – исходное содержимое записываемого файла.

name – строка, содержащая имя файла

Attachment_type — одно из значений allure.attachment_type

расширение – предоставленное расширение, которое будет использоваться для создания файла.

или allure.attach.file(источник, имя, тип_вложения, расширение)

source – строка, содержащая путь к файлу.

Язык кода:javascript
копировать
# -*- coding: utf-8 -*-
# @Time : 2019/3/12 11:46
# @Author : zzt

import allure
import pytest

@allure.feature('Это метка первого уровня')
class TestAllure():

    @allure.title("Заголовок варианта использования 0")
    @allure.story("Это первый второстепенный тег")
    @pytest.mark.parametrize('param', ['бронза', 'серебро', 'золото'])
    def test_0(self, param):
        allure.attach('Содержимое вложения: '+param, «Я — имя вложения», allure.attachment_type.TEXT)

    @allure.title("Заголовок варианта использования 1")
    @allure.story("Это второй дополнительный тег")
    def test_1(self):
        allure.attach.file(r'E:\Myproject\pytest-allure\test\test_1.jpg', 'Я - имя на прикрепленном скриншоте', attachment_type=allure.attachment_type.JPG)

    @allure.title("Заголовок варианта использования 2")
    @allure.story("Это третий дополнительный тег")
    @allure.severity(allure.severity_level.NORMAL)
    def test_2(self):
        pass

Результат выполненияследующее:

4. Исходный код: Github: https://github.com/linda883/py_techDemo.

5. CI/CD использует Jenkins для непрерывной интеграции.

Я считаю, что все знают, как интегрироваться в Jenkins, поэтому я не буду об этом говорить, или вы можете прочитать мой блог о непрерывной интеграции.

Издатель: Лидер стека программистов полного стека, укажите источник для перепечатки: https://javaforall.cn/164415.html Исходная ссылка: https://javaforall.cn

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose