Всем привет, мы снова встретились, я ваш друг Цюаньчжаньцзюнь.
**
:1. Простой, гибкий и простой в использовании; поддерживает параметризацию; тествариант использованияизskipиxfail иметь дело с; 2. Он может поддерживать простое модульное тестирование и сложное функциональное тестирование, а также может использоваться для Автоматизированное тестирование, такое как Selenium/Appium и автоматическое тестирование интерфейса. (pytest+requests); 3. pytest имеет множество сторонних плагинов, его можно настраивать и расширять. лучше Используется как pytest-allure (генерация идеального отчета о тестировании в формате HTML) pytest-xdist (многопроцессорное распределение) и т. д.; 4. Может хорошо интегрироваться с Jenkins;** 5. **
: установка pytest, импорт связанных зависимых библиотек. Pip install –U pytest U означает обновление Пип установить сахар pip install pytest-rerunfailures Pip установить pytest-xdist Pip install pytest-предполагать Pip intall pytest-html… Просмотр списка пипсов pytest -h помощь**
Структура фреймворка Pytest Импорт pytest аналогичен настройке, демонтаж также более гибок, а также есть session().
уровень модуля (setup_module/ teardown_module) Функции, не входящие в класс, полезны функциональный уровень (setup_function/ teardown_function) Функции, не входящие в класс, полезны уровень класса (setup_class/ Teardown_class) только в Пробегите один раз до и после занятия. уровень метода (setup_method/ teardown_methond) Начало и конец методов, выполняемых в классе
Как выполняется pytest Pytest/py.test (терминал, командная строка, pycharm можно настроить для выполнения в режиме pytest)
pytest.xfail() Мы уже узнали, как пропустить выполнение тестовых случаев. Один из способов — использовать метод pytest.skip() в тестовой функции. pytest.xfail(), который мы собираемся сейчас изучить, чем-то похож на pytest.skip(), за исключением того, что его смысл таков: пометить вариант использования как сбой xfail, и последующий код в варианте использования не будет выполнен.
Соблюдаются старые правила: когда мы вызываем метод pytes.xfail() в тестовом примере, мы можем передать параметр причины, чтобы указать причину.
Файл #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 в тестовый пример.
Файл #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, а не как пройденный.
1. отметка В следующем случае отметьте test_send_http() как webtest.
# 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».
pytest -v -m “not webtest”
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'"])
2.-v Указанный идентификатор функционального узла Если вы хотите указать вариант использования в классе в определенном модуле .py, например вариант использования testmethod в TestClass Для каждого варианта использования, который начинается с test (или заканчивается на _test), именем функции (или метода) является идентификатор узла варианта использования. Используйте -v, чтобы указать идентификатор узла для запуска. параметр
pytest -v test_server.py::TestClass::test_method
Конечно, вы также можете запустить весь класс.
pytest -v test_server.py::TestClass
Вы также можете выбрать несколько узлов для запуска и разделить несколько узлов пробелами.
pytest -v test_server.py::TestClass test_server.py::test_send_http
.-k Сопоставить название варианта использования Это можно указать с помощью параметра командной строки -k в Сопоставить. название варианта использованияизвыражение
pytest -v -k http
Вы также можете запустить все тесты и исключить определенные случаи на основе их названий:
pytest -k “not send_http” -v
Вы также можете выбрать одновременное соответствие «http» и «quick».
pytest -k “http or quick” -v
Ниже приведены практические детали — приспособления действительно потрясающие.
По сравнению с unittest, самым передовым моментом pytest, вероятно, является механизм фиксации.
Для unittest setUp и TearDown необходимо записать в классе каждого варианта использования. Это то, что мы называем пре- и постпозицией.
Неизбежно, что предварительная и постобработка многих вариантов использования одинакова (например, многие варианты использования требуют входа в систему спереди и выхода сзади), поэтому нам приходится многократно копировать и вставлять, что приводит к увеличению рабочая нагрузка и объем кода. Интерфейс также кажется громоздким.
Итак, в это времяМеханизм фиксации в pytest вот-вот дебютирует.。
С точки зрения непрофессионала: приспособление = передняя часть + стойка.
Удобство в том, что если многие варианты использования имеют одинаковый префикс и постфикс, то я могу реализовать только один, а затем просто вызвать нужный вариант использования.
1. Механизм: создайте файл conftest.py на том же уровне, что и тестовый пример, или родительском для тестового примера. 2. В файл conftest.py: поместите все префиксы и постфиксы. Нет необходимости в файле use case.py активно вводить файл conftest. 3. Определить функцию: включая предоперационную + послеоперационную. 4. Объявите функцию как фикстуру :Добавить перед функцией @pytest.fixture(уровень действия = по умолчанию — функция) 5.Определение приспособления. Если есть возвращаемое значение, напишите его после доходности. (Функция доходности эквивалентна возврату) В тестовом примере, когда вызывается функция фиксации с возвращаемым значением, имя функции представляет возвращаемое значение. существоватьтествариант использованиякогдасередина,Имя функции можно использовать в качестве варианта использования.
@pytest.fixture(scope="class") #Определение области видимости
def open_url():
# префикс
driver = webdriver.Chrome()
driver.get(url) #url — адрес ссылки
yield driver #yieldпредыдущий коддапрефикс,После этого код «Из Задний».
# Задний
driver.quit()
Таким образом мы определяем приспособление под названием open_url.
Вы можете напрямую вызвать pre и post, определенные выше
Вы можете видеть, что в классе TestLogin мы больше не пишем настройку и демонтаж. Мы можем просто написать наш промежуточный процесс напрямую. Разве это не очень удобно?
Как показано на рисунке выше, вы можете видеть, что мой класс также ссылается на приспособление с именем обновить_страницу. Перейдите непосредственно к коду:
# обновить страницу - Определите второй прибор
@pytest.fixture
def refresh_page(open_url):
yield
open_url.refresh()
Open_url напрямую используется как предварительная ссылка на другой прибор, разделенный выходом. После того, как предварительная и пост-ссылка open_url выполняются в варианте использования, пост-ссылка обновления выполняется снова. Порядок выполнения: код перед выходом open_url – код варианта использования – код после выхода open_url –> код после выходом обновления_страницы Разве это не чудесно? Это может решить проблему, когда многие процессы вариантов использования взаимосвязаны.
Конечно, нет. Устройство уже определило свой домен варианта использования в conftest.py, и оно возьмет на себя инициативу, чтобы определить, в каком домене варианта использования действует ваше устройство. Во-первых, давайте взглянем на определение функции фиксации в рамках:
Область — это область, определяющая область варианта использования: функция: область действия по умолчанию, будет вызываться каждая функция или метод, они будут вызываться, если они не заполнены. класс: вызывается один раз для каждого класса module: Вызывается один раз для каждого файла .py. В файле может быть несколько функций и классов. Сеанс: вызывается один раз несколькими файлами и может охватывать файлы. Например, в файле .py каждый файл .py является модулем. объем: session > module > class > function
Таким образом, различные устройства не будут конфликтовать друг с другом при вызове.
Пример автоматического вызова: ** Когда существует много вариантов использования управления, этот метод более удобен и эффективен, но вы должны быть осторожны при использовании этой функции и обязательно обращать внимание на область действия фикстуры. Следует отметить, что при использовании этого метода нельзя использовать функцию возвращаемого значения. По умолчанию для 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 для установки области на уровне функции. Вызывается один раз перед каждым вариантом использования, используется автоматически
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"])
Результат выполнения
----Начать выполнение модуля------
module : autouse
------Запустить браузер-------
function:test_01
--Вернуться на главную--
.----Сценарий использования 01-----
function:test_02
--Вернуться на главную--
.---- Вариант использования 02 -----
------Конец теста end!----------
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
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
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
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% ██████████
Сценарий: естественный порядок выполнения не учитывается или вы хотите изменить порядок выполнения, например добавив Сначала должен быть выполнен вариант использования данных, а затем вариант использования удаления. По умолчанию тестовые случаи указаны по имени. Называется последовательным выполнением. • решать: • Установка: пип install pytest-ordering • Добавьте следующий декоратор в тестовый метод •@pytest.mark.last —Последняя казнь • @pytest.mark.run(order=1) — какое выполнение По умолчанию pytest выполняется в алфавитном порядке.
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
• Его можно остановить только после завершения обычного выполнения. Если вы хотите остановить тест при возникновении ошибки: -x Вы также можете прекратить тестирование, когда количество n ошибок вариантов использования достигнет указанного числа: - – maxfail=n • осуществлять: • pytest -x -v -s имя_файла.py ——- -x останавливается при возникновении ошибки • pytest -x -v -s имя_файла.py —maxfail=2 ——- –maxfail=2 Он останавливается, когда обнаруживает две ошибки.
**Сценарий: • Когда тест не пройден и повторяется n раз, добавляется задержка между повторами. время, а затем запустите снова через n секунд. • осуществлять: • Установка: пип install pytest-rerunfailures • pytest -v – -reruns 5 –reruns-delay 1 —Подождите 1 секунду каждый раз Повторить попытку 5 раз
pip3 install pytest-assume продолжает выполнение после подтверждения, но необходимо изменить утверждение**
@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)
Сценарий: 1000 тестовых примеров, выполнение одного тестового примера занимает 1 минуту, выполнение одного тестировщика занимает 1000 минут. колокол. Обычно мы обмениваем затраты на рабочую силу на затраты времени. Если мы добавим несколько человек для совместной работы, время сократится. короткий. Если 10 людям потребуется всего 100 минут, чтобы выполнить его вместе, это параллельное тестирование и распределенный сценарий. решить: плагин распределенного выполнения pytest: pytest-xdist, выполнение на нескольких процессорах или хостах Предпосылка: все варианты использования независимы и не имеют последовательности. Они могут выполняться случайным образом и повторяться. Влияние на другие варианты использования. Установка:Pip3 install pytest-xdist • Несколько процессоров выполняют вариант использования параллельно, напрямую добавьте -n 3 — количество параллелизма: pytest -n 3 • Выполнять вместе под несколькими терминалами
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 — имя проекта.
│ 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
Ссылка на код:
# 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 секунды.
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 секунды, что значительно сокращает время варианта использования.
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 ===========================
Я не буду здесь вдаваться в подробности. Если вам это нравится, вы можете изучить это самостоятельно.
Выполнение unitest происходит так же, как и раньше. Старайтесь не смешивать и использовать какие-то причудливые варианты. Просто используйте тот, который вам нравится. Я не буду здесь вдаваться в подробности.
pytest-HTML — это плагин, используемый pytest для создания HTML-отчетов о результатах тестирования. Совместимость с Python 2.7,3.6.
pytest-html 1. Адрес исходного кода на github [https://github.com/pytest-dev/pytest-html]
2.pip-установка
$ pip install pytest-html
3.Метод выполнения
$ pytest --html=report.html
HTML-отчет 1. Откройте cmd, перейдите в каталог, в котором вам нужно выполнить тестовый пример pytest, и выполните команду: pytest –html=report.html
2. После выполнения в текущем каталоге будет создан файл отчета report.html, эффект отображения будет следующим:
Укажите путь к отчету 1. Отчет, созданный путем прямого выполнения «pytest –html=report.html», будет находиться по тому же пути, что и текущий скрипт. Если вы хотите указать место хранения отчета, поместите его в папку отчета в том же каталоге. текущего сценария.
pytest --html=./report/report.html
2. Если вы хотите указать вариант использования для выполнения определенного файла .py и всех вариантов использования в определенной папке, вам необходимо добавить параметр. Конкретные правила можно найти в [pytest document 2 — правила выполнения вариантов использования]
Отчеты отображаются независимо 1. CSS отчета, созданного указанным выше методом, независим. Стиль будет потерян при совместном использовании отчета. Чтобы лучше делиться отчетом и отображать его по электронной почте, вы можете объединить стиль CSS в HTML.
$ pytest --html=report.html --self-contained-html
Показать параметры По умолчанию все строки в таблице «Результаты» будут развернуты, кроме строк с «Пройдено тестов».
Это поведение можно настроить с помощью параметра запроса: ?collapsed=Passed,XFailed,Skipped.
Дополнительные возможности 1. Дополнительные функции можно найти в официальной документации [https://github.com/pytest-dev/pytest-html].
Информация об отладке автоматических тестовых случаев очень полезна. Она позволяет нам узнать текущий статус выполнения, какой этап выполнения, соответствующую информацию об ошибках и т. д. Иногда ее можно найти в pytest. Иногда выводится не вся информация, например информация о проходе. test по умолчанию. Вариант использования не имеет вывода на печать. В этой статье рассказывается, как отображать всю информацию журнала в реальном времени в pytest.
1. Используйте печать для вывода информации журнала slowTest_print.py
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(), информация журнала не отображается, и печать не отображается.
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 ниже также отображает информацию, связанную с печатью.
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 предоставляет модуль журналирования, который может записывать то, что мы делаем. Хочу Вся информация сохраняется в файле журнала для удобного просмотра.
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
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.
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 ======================
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 для вывода информации журнала в режиме реального времени. Пожалуйста, запустите следующую программу самостоятельно. Вы можете видеть, что программа выводит статус выполнения текущего тестового примера в режиме реального времени.
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 для вывода всей информации журнала в режиме реального времени при запуске тестовых случаев.
1. Часть 1 (—- pytest-cov) Введение: pytest-cov Это плагин pytest, и его суть тоже справочная. python coverage Библиотека Используется для подсчета покрытия кода. Следующая статья предназначена только для понимания. В реальных проектах мы все используем API для вызова интерфейса, поэтому использование реальных проектов будет более сложным. Это будет объяснено в следующий раз.
Дополнительно: покрытие Причина в том, что освещение является разновидностью покрытия утверждений. Оно не может интерпретировать вашу логику. Если оно действительно имеет смысл, его необходимо объединить с самим проектом. Эти данные о покрытии не очень убедительны, поэтому не следуйте им вслепую. Вообще говоря: покрытие пути > Охват решений > покрытие заявлений
Установить
pip install pytest-cover
Установить После окончания там
py.test -h можно увидеть имеет следующее использование,иллюстрировать Установитьуспех:
coverage reporting with distributed testing support:
пример Создайте три новых файла: cau.py и test_conver.py в том же коде каталога. Файл run.py находится в каталоге верхнего уровня pp. Взаимосвязь кода следующая.
1. Создайте новый файл функции cau.py.
#!/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:
#!/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.
#!/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 Просто запусти это
coveragerc Означает пропуск определенных скриптов из теста покрытия. Файл test_cover.py и файл инициализации здесь пропускаются.
Содержание следующее:
[run]
omit =
tests/*
*/__init__.py
*/test_cover.py
результат После генерации вы можете напрямую щелкнуть indexhtml.
Вы можете увидеть следующий статус выполнения: Зеленый означает выполнение, красный — не выполнение. Проверьте логику кода самостоятельно и сделайте вывод, что результат верен.
Вторая: Следующая глава (— coverage.py api) Использование pytest-cov Невозможно использовать для статистики Охват тестовых сценариев для служб вызовов API покрыт, но большинство проектов в основном используют вызовы API. Поэтому нам дополнительно нужно использовать Cover.py api Давайте посчитаем. Когда вы устанавливаете Pytest-cov, значение «Установить покрытие» уже установлено по умолчанию. Это Библиотека.
Запуск службы Чтобы сканировать код, при запуске службы необходимо вставить конфигурацию, связанную с покрытием. Я запустил flask здесь, поэтому добавил его в код запуска flask следующим образом:
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 представляет исполняемый файл.
coverage run --source='/xxx/' xx.py
Схема работы запуска следующая:
Затем вызовите свой сценарий автоматизации (сценарий автоматизации напрямую вызывает API, предоставляемый службой).
Если автоматизация работает нормально, вы можете увидеть запущенные запросы.
Вышеупомянутое показывает, что с вашим скриптом и сервисом проблем нет.
После того, как ctr-c останавливает сценарий, наконец отображается сохранение. Если отображается сообщение «Предупреждение Coverage.py: данные не собраны. (данные не собраны)», значит, возникла проблема с работой службы. служба не работает с вашим кодом.
Генерация отчета Введите следующую команду
coverage report
Введите последний шаг на последнем шаге
coverage html
Это сохраняет html-файлы.
Чтобы просмотреть экспорт в окне, нажмите на конкретный файл и нажмите «Выполнить». Вы увидите, что зеленый файл запущен. Но проблема в том, что вы обнаружите, что какой-то код должен быть выполнен, но не выполняется. Поэтому сложно сказать, точны ли данные о покрытии.
Pytest+allure теперь объединен с jenkins. Я считаю, что это может сделать каждый. Если вы этого не знаете, вы можете посмотреть другой мой блог о непрерывной интеграции.
Индивидуальные отчеты Особенность: Отметьте основные функциональные модули История: Отметьте функции ветвления в функциональном модуле «Функции». Серьезность: отметьте уровень важности тестового примера. Шаг: важные шаги по маркировке тестовых примеров Проблема и TestCase: отметьте «Проблему» и «Случай» и добавьте URL-адрес.
1. Подробное объяснение настройки функций.
# -*- 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. Подробное объяснение настройки истории.
# -*- 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. Подробное объяснение названия варианта использования и настройки описания варианта использования.
# -*- 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、 Тривиальный уровень: незначительные дефекты (нет запроса на ввод необходимых элементов или запрос неправильный).
# -*- 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. Подробное объяснение настройки шага.
# -*- 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.
# -*- 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. Подробное объяснение настройки прикрепления.
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, и отображение отчета показано на рисунке ниже.
С увеличением функций программного обеспечения появляется все больше и больше модулей, что также означает все больше и больше вариантов использования. Чтобы сэкономить время выполнения и быстро получить отчеты и результаты испытаний, вы можете быстро выполнить варианты использования, запустив указанные варианты использования на работе. .
Пример каталога
spec_sub1_modul_test.py
#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
#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
#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"
Запустить указанный модуль
if __name__ == '__main__':
pytest.main("-v -s spec_001_modul_test.py")
Запуск пакетных папок (запуск всех вариантов использования в текущей папке, включая подпапки)
#coding: UTF-8
import pytest
if __name__ == '__main__':
pytest.main("-v -s ./")
Запустите указанную папку (все варианты использования в каталоге subpath1)
#coding: UTF-8
import pytest
if __name__ == '__main__':
pytest.main("-v -s subpath1/")
Запустите указанный вариант использования в модуле (вариант использования test_001_spec в работающем модуле)
if __name__ == '__main__':
pytest.main("-v -s spec_001_modul_test.py::test_001_spec")
Запустите вариант использования, указанный в классе (запустите метод test_003_spec класса Test_Class в модуле)
if __name__ == '__main__':
pytest.main("-v -s spec_001_modul_test.py::Test_Class::test_003_spec")
Случай нечеткого соответствия (соответствует текущему каталогу, указанному ниже)
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')
Эта отметка используется для определения уровня тестовых примеров или тестовых классов, которые разделены на пять уровней: блокирующий, критический, нормальный, второстепенный и тривиальный. Отметим тестовые сценарии по уровням и просмотрим отчет о тестировании.
1. название дела, заголовок
Вы можете настроить заголовок варианта использования, который по умолчанию соответствует имени функции.
@allure.title
# -*- 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
Эффект исполнения:
Можно добавить подробные описания теста, чтобы предоставить читателю отчета столько контекста, сколько необходимо.
Два способа: @allure.description предоставляет декоратор, описывающий строку.
@allure.description_html предоставляет некоторый HTML-код в части описания тестового примера (будет изучен).
# -*- 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
@allure.link @allure.issue @allure.testcase
# -*- 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
Результат выполненияследующее:
Отчеты могут отображать множество различных типов вложений, дополняющих тесты, шаги и т. д.
allure.attach(body, name, attachment_type, extension)
body – исходное содержимое записываемого файла.
name – строка, содержащая имя файла
Attachment_type — одно из значений allure.attachment_type
расширение – предоставленное расширение, которое будет использоваться для создания файла.
или allure.attach.file(источник, имя, тип_вложения, расширение)
source – строка, содержащая путь к файлу.
# -*- 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
Результат выполненияследующее:
Я считаю, что все знают, как интегрироваться в Jenkins, поэтому я не буду об этом говорить, или вы можете прочитать мой блог о непрерывной интеграции.
Издатель: Лидер стека программистов полного стека, укажите источник для перепечатки: https://javaforall.cn/164415.html Исходная ссылка: https://javaforall.cn