目录
安装
用法
基本报告
支持 Pytest features
Xfail
条件标记
Fixtures and Finalizers
参数化
Allure Features
Steps
附件
描述
标题
链接
重试
BDD 标签
严重性标记
Behave
安装
使用
Features
严重性
步骤和场景状态
步骤数据
Pytest可从PyPI进行安装,因此建议使用pip进行安装。要安装最新版本,请从命令行执行:
$ pip install allure-pytest
这将安装allure pytest和allure python-commons包,以生成与allure2兼容的报告数据。如果第一代allure 报告使用的是以前版本的适配器,则需要首先卸载它。
要使Allure侦听器能够在测试执行期间收集结果,只需添加--alluredir选项并提供应存储结果的文件夹的路径。例如:
$ pytest --alluredir=/tmp/my_allure_results
要在测试完成后查看实际报告,您需要使用Allure命令行实用程序根据结果生成报告。
$ allure serve /tmp/my_allure_results
此命令将在默认浏览器中显示生成的报告。
您可以在Allure报告中看到所有默认的pytest状态:只有由于其中一个断言错误而未成功的测试才会被标记为失败,任何其他异常都会导致测试处于中断状态。
import pytest
def test_success():
"""this test succeeds"""
assert True
def test_failure():
"""this test fails"""
assert False
def test_skip():
"""this test is skipped"""
pytest.skip('for a reason!')
def test_broken():
raise Exception('oops')
Allure报告支持的一些常见Pytest特性包括xfail、fixture和finalizer、标记、条件跳过和参数化。
这是标记预期失败的pytest方法:(pytest文档)
@pytest.mark.xfail(condition=lambda: True, reason='this test is expecting failure')
def test_xfail_expected_failure():
"""this test is an xfail that will be marked as expected failure"""
assert False
@pytest.mark.xfail(condition=lambda: True, reason='this test is expecting failure')
def test_xfail_unexpected_pass():
"""this test is an xfail that will be marked as unexpected success"""
assert True
这导致测试被跳过,并在预期失败时用特殊标记进行标记。
以及描述中的特殊标记和意外通过时的特殊标签。
在Pytest中,您可以有条件地将测试标记为在某些特定条件下不执行(Pytest docs):
@pytest.mark.skipif('2 + 2 != 5', reason='This test is skipped by a triggered condition in @pytest.mark.skipif')
def test_skip_by_triggered_condition():
pass
当条件求值为true时,测试将在报告中接收“Skipped”状态、来自装饰器的标记和描述。
fixture和finalizer是Pytest将分别在测试开始前和测试结束后调用的实用函数。Allure跟踪每个fixture的调用,并详细显示调用了哪些方法和哪些参数,从而保留了正确的调用顺序。 (Pytest docs)
您不需要标记您的固定装置以使其在报告中可见,它们将自动检测到不同的skope。
@pytest.fixture(params=[True, False], ids=['param_true', 'param_false'])
def function_scope_fixture_with_finalizer(request):
if request.param:
print('True')
else:
print('False')
def function_scope_finalizer():
function_scope_step()
request.addfinalizer(function_scope_finalizer)
@pytest.fixture(scope='class')
def class_scope_fixture_with_finalizer(request):
def class_finalizer_fixture():
class_scope_step()
request.addfinalizer(class_finalizer_fixture)
@pytest.fixture(scope='module')
def module_scope_fixture_with_finalizer(request):
def module_finalizer_fixture():
module_scope_step()
request.addfinalizer(module_finalizer_fixture)
@pytest.fixture(scope='session')
def session_scope_fixture_with_finalizer(request):
def session_finalizer_fixture():
session_scope_step()
request.addfinalizer(session_finalizer_fixture)
class TestClass(object):
def test_with_scoped_finalizers(self,
function_scope_fixture_with_finalizer,
class_scope_fixture_with_finalizer,
module_scope_fixture_with_finalizer,
session_scope_fixture_with_finalizer):
step_inside_test_body()
根据夹具执行的结果,依赖它的测试可能会收到不同的状态。fixture中的异常将使所有依赖测试中断,pytest.skip()调用将使所有从属测试跳过。
import pytest
@pytest.fixture
def skip_fixture():
pytest.skip()
@pytest.fixture
def fail_fixture():
assert False
@pytest.fixture
def broken_fixture():
raise Exception("Sorry, it's broken.")
def test_with_pytest_skip_in_the_fixture(skip_fixture):
pass
def test_with_failure_in_the_fixture(fail_fixture):
pass
def test_with_broken_fixture(broken_fixture):
pass
您可以使用从输入参数集生成许多测试用例 @pytest.mark.parametrize
. (Pytest docs)
所有参数名称和值都将在报告中捕获,也可以选择将参数名称替换为ids kwarg中提供的字符串描述。
import allure
import pytest
@allure.step
def simple_step(step_param1, step_param2 = None):
pass
@pytest.mark.parametrize('param1', [True, False], ids=['id explaining value 1', 'id explaining value 2'])
def test_parameterize_with_id(param1):
simple_step(param1)
@pytest.mark.parametrize('param1', [True, False])
@pytest.mark.parametrize('param2', ['value 1', 'value 2'])
def test_parametrize_with_two_parameters(param1, param2):
simple_step(param1, param2)
@pytest.mark.parametrize('param1', [True], ids=['boolean parameter id'])
@pytest.mark.parametrize('param2', ['value 1', 'value 2'])
@pytest.mark.parametrize('param3', [1])
def test_parameterize_with_uneven_value_sets(param1, param2, param3):
simple_step(param1, param3)
simple_step(param2)
使用不同的命名和未命名参数集捕获的测试调用的示例。
具有命名参数的参数化测试的测试执行详细信息。
Allure目前几乎支持所有可用的功能,除了Pytest环境。
Allure报告的第一个可能也是最重要的方面是,它允许获得每个测试调用的非常详细的逐步表示。通过@allure.step decorator可以实现这一点,该decorator向报告添加了对带有所提供参数的注释方法或函数的调用。
用@step注释的方法可以存储在测试之外,并在需要时导入。步骤方法可以具有任意深度的嵌套结构。
import allure
import pytest
from .steps import imported_step
@allure.step
def passing_step():
pass
@allure.step
def step_with_nested_steps():
nested_step()
@allure.step
def nested_step():
nested_step_with_arguments(1, 'abc')
@allure.step
def nested_step_with_arguments(arg1, arg2):
pass
def test_with_imported_step():
passing_step()
imported_step()
def test_with_nested_steps():
passing_step()
step_with_nested_steps()
每个步骤的状态都显示在名称右侧的一个小图标中。嵌套步骤以树状可折叠结构进行组织。
步骤可以有一个描述行,该行支持传递的位置参数和关键字参数的占位符。关键字参数的默认参数也将被捕获。
import allure
@allure.step('Step with placeholders in the title, positional: "{0}", keyword: "{key}"')
def step_with_title_placeholders(arg1, key=None):
pass
def test_steps_with_placeholders():
step_with_title_placeholders(1, key='something')
step_with_title_placeholders(2)
step_with_title_placeholders(3, 'anything')
台阶也由固定装置支撑。下面是一个使用conftest.py模块中定义的fixture的测试示例(即使不直接导入,这样的fixture也会由Pytest解析):
conftest.py
import allure
import pytest
@allure.step('step in conftest.py')
def conftest_step():
pass
@pytest.fixture
def fixture_with_conftest_step():
conftest_step()
import allure
from .steps import imported_step
@allure.step
def passing_step():
pass
def test_with_step_in_fixture_from_conftest(fixture_with_conftest_step):
passing_step()
固定装置中的步骤显示在单独的树中,用于setup和teardown。
报告可以显示提供的许多不同类型的附件,这些附件可以补充测试、步骤或夹具结果。附件可以通过调用诱惑来创建。attach(body,name,attachment_type,extension):
body
- 要写入文件的原始内容。
name
- 包含文件名的字符串
attachment_type
-attachment_type-allure.attachment_type值之一
extension
- 扩展名-将被用作创建文件的扩展名。
或allure.attach.file(源、名称、附件类型、扩展名):
source
- 包含文件路径的字符串。
(其他参数类似)
import allure
import pytest
@pytest.fixture
def attach_file_in_module_scope_fixture_with_finalizer(request):
allure.attach('A text attacment in module scope fixture', 'blah blah blah', allure.attachment_type.TEXT)
def finalizer_module_scope_fixture():
allure.attach('A text attacment in module scope finalizer', 'blah blah blah blah',
allure.attachment_type.TEXT)
request.addfinalizer(finalizer_module_scope_fixture)
def test_with_attacments_in_fixture_and_finalizer(attach_file_in_module_scope_finalizer):
pass
def test_multiple_attachments():
allure.attach.file('./data/totally_open_source_kitten.png', attachment_type=allure.attachment_type.PNG)
allure.attach(' a page ', 'Attach with HTML type', allure.attachment_type.HTML)
附件显示在所属测试实体的上下文中。HTML类型的附件呈现并显示在报告页面上。这是一种方便的方式,可以为您自己的测试结果表示提供一些自定义。
您可以添加测试的详细描述,以便根据需要为报表读取器提供尽可能多的上下文。这可以通过几种方式实现:您可以添加一个提供描述字符串的@allure.description装饰器,也可以使用@allre.description_html提供一些要在测试用例的“描述”部分中呈现的html。或者,描述将简单地从测试方法的文档字符串中提取。
import allure
@allure.description_html("""
Test with some complicated html description
Firstname
Lastname
Age
William
Smith
50
Vasya
Jackson
94
""")
def test_html_description():
assert True
@allure.description("""
Multiline test description.
That comes from the allure.description decorator.
Nothing special about it.
""")
def test_description_from_decorator():
assert 42 == int(6 * 7)
def test_unicode_in_docstring_description():
"""Unicode in description.
Этот тест проверяет юникод.
你好伙计.
"""
assert 42 == int(6 * 7)
描述支持unicode字符串:
从description_HTML呈现的HTML:
此外,可以使用allure.dynamic.description从测试体内动态更新描述。
import allure
@allure.description("""
This description will be replaced at the end of the test.
""")
def test_dynamic_description():
assert 42 == int(6 * 7)
allure.dynamic.description('A final description.')
使用特殊的@allure.title装饰器可以使测试标题更具可读性。标题支持参数占位符,并支持动态替换。
import allure
import pytest
@allure.title("This test has a custom title")
def test_with_a_title():
assert 2 + 2 == 4
@allure.title("This test has a custom title with unicode: Привет!")
def test_with_unicode_title():
assert 3 + 3 == 6
@allure.title("Parameterized test title: adding {param1} with {param2}")
@pytest.mark.parametrize('param1,param2,expected', [
(2, 2, 4),
(1, 2, 5)
])
def test_with_parameterized_title(param1, param2, expected):
assert param1 + param2 == expected
@allure.title("This title will be replaced in a test body")
def test_with_dynamic_title():
assert 2 + 2 == 4
allure.dynamic.title('After a successful test finish, the title was replaced with this line.')
要将报告与错误跟踪器或测试管理系统集成,Allure具有@Allure.link、@Allure.issue和@Allure.testcase描述符。
import allure
TEST_CASE_LINK = 'https://github.com/qameta/allure-integrations/issues/8#issuecomment-268313637'
@allure.link('https://www.youtube.com/watch?v=4YYzUTYZRMU')
def test_with_link():
pass
@allure.link('https://www.youtube.com/watch?v=Su5p2TqZxKU', name='Click me')
def test_with_named_link():
pass
@allure.issue('140', 'Pytest-flaky test retries shows like test steps')
def test_with_issue_link():
pass
@allure.testcase(TEST_CASE_LINK, 'Test case title')
def test_with_testcase_link():
pass
@allure.link将在“链接”部分提供指向所提供url的可点击链接:
@allure.issue将提供一个带有小错误图标的链接。此描述符将测试用例id作为输入参数,以便将其与所提供的问题链接类型的链接模板一起使用。链接模板在Pytest的--plure链接模式配置选项中指定。必须使用冒号指定链接模板和类型:
$ pytest directory_with_tests/ --alluredir=/tmp/my_allure_report \
--allure-link-pattern=issue:http://www.mytesttracker.com/issue/{}
模板关键字是issue、link和test_case,为相应类型的链接提供模板。
诱惑允许您聚合关于在单个测试运行期间重新执行的测试的信息,以及一段时间内测试执行的历史记录。
对于重试,您可以使用Pytest重新运行失败插件。
例如,如果我们有一个非常不可靠的步骤方法,但经常失败,在Pytest启动选项中指定--reruns=5后,我们会在Retries选项卡上显示所有运行此测试的失败尝试。
import allure
import random
import time
@allure.step
def passing_step():
pass
@allure.step
def flaky_broken_step():
if random.randint(1, 5) != 1:
raise Exception('Broken!')
def test_broken_with_randomized_time():
passing_step()
time.sleep(random.randint(1, 3))
flaky_broken_step()
同样,这样的测试会在执行的测试列表中收到“片状”炸弹图标。
有时,您希望能够灵活地处理要执行的测试。Pytest通过使用标记[email protected](Pytest文档)来实现这一点。
Allure允许使用3种类型的标记装饰器以类似的方式标记测试,这些标记装饰器允许构建报告的表示:
BDD风格的标记表示史诗、特色和故事
严重性标签
自定义标签
有两个装饰器:@allure.feature和@allure.story,用于根据您项目的功能/故事细分来标记您的测试(有关背景信息,请参阅维基百科上的BDD文章)。要标记某个特征或故事属于史诗,请使用以epic_前缀开头的名称。
tests.py
import allure
def test_without_any_annotations_that_wont_be_executed():
pass
@allure.story('epic_1')
def test_with_epic_1():
pass
@allure.story('story_1')
def test_with_story_1():
pass
@allure.story('story_2')
def test_with_story_2():
pass
@allure.feature('feature_2')
@allure.story('story_2')
def test_with_story_2_and_feature_2():
pass
您可以使用以下命令行选项指定要执行的不同测试集,并传递逗号分隔的值列表:
--allure-epics
--allure-features
--allure-stories
例如:
$ pytest tests.py --allure-stories story_1,story_2
collected 5 items
tests.py ... [100%]
============================== 3 passed in 0.01 seconds ==============================
$ pytest tests.py --allure-features feature2 --allure-stories story2
collected 5 items
tests.py ... [100%]
=============================== 2 passed in 0.01 seconds ==============================
要按严重性级别标记测试,可以使用@allure.severity decorator。它以allure.severity_level枚举值为参数。
tests.py
import allure
def test_with_no_severity_label():
pass
@allure.severity(allure.severity_level.TRIVIAL)
def test_with_trivial_severity():
pass
@allure.severity(allure.severity_level.NORMAL)
def test_with_normal_severity():
pass
@allure.severity(allure.severity_level.NORMAL)
class TestClassWithNormalSeverity(object):
def test_inside_the_normal_severity_test_class(self):
pass
@allure.severity(allure.severity_level.CRITICAL)
def test_inside_the_normal_severity_test_class_with_overriding_critical_severity(self):
pass
Severity decorator可以应用于函数、方法或整个类。
通过使用带有逗号分隔的严重性级别列表的--plure severties命令行选项,将只运行具有相应严重性的测试。
$ pytest tests.py --allure-severities normal,critical
collected 5 items
bdd_annotations_demo/test_severity_labels.py ... [100%]
================================ 3 passed in 0.01 seconds ============================
诱惑与behavior集成为一个外部格式化程序。
$ pip install allure-behave
您可以直接在命令行中指定格式化程序:
$ behave -f allure_behave.formatter:AllureFormatter -o %allure_result_folder% ./features
与严重性名称匹配的标签(如关键、琐碎等)将被解释为功能或场景严重性。如果没有提供,场景将继承功能严重性,或者在其他情况下覆盖它。如果存在多个严重性定义标记,则只使用最后一个。
具有断言异常的步骤将被标记为失败。在测试执行过程中引发的其他异常将导致其状态被破坏。场景状态将由第一个不成功的步骤状态决定。当所有步骤都通过了,那么整个场景就被认为通过了。
步骤数据文本或表格数据在报告中表示为步骤附件