diff --git a/allure/__init__.py b/allure/__init__.py
index 14a1564..ef6e621 100644
--- a/allure/__init__.py
+++ b/allure/__init__.py
@@ -2,7 +2,7 @@
# providing decorators via allure.xxx instead of pytest.allure.xxx
-__methods_to_provide = ['step', 'attach', 'single_step', 'label', 'feature', 'story']
+__methods_to_provide = ['step', 'attach', 'single_step', 'label', 'feature', 'story', 'severity']
for method in __methods_to_provide:
globals()[method] = getattr(MASTER_HELPER, method)
diff --git a/allure/common.py b/allure/common.py
index f16d7eb..842069b 100644
--- a/allure/common.py
+++ b/allure/common.py
@@ -12,7 +12,7 @@
from lxml import etree
import py
-from allure.constants import AttachmentType, Severity, Status
+from allure.constants import AttachmentType, Status
from allure.structure import Attach, TestStep, TestCase, TestSuite, Failure
from allure.utils import now
@@ -27,7 +27,7 @@ def __enter__(self):
if self.allure:
self.step = self.allure.start_step(self.title)
- def __exit__(self, exc_type, exc_val, exc_tb): # @UnusedVariable
+ def __exit__(self, exc_type, exc_val, exc_tb):
if self.allure:
if exc_type is not None:
if exc_type == Skipped:
@@ -102,7 +102,7 @@ def attach(self, title, contents, attach_type):
"""
attach = Attach(source=self._save_attach(contents, attach_type=attach_type),
title=title,
- type=attach_type)
+ type=attach_type.mime_type)
self.stack[-1].attachments.append(attach)
def start_step(self, name):
@@ -126,14 +126,12 @@ def stop_step(self):
step = self.stack.pop()
step.stop = now()
- def start_case(self, name, description=None, severity=Severity.NORMAL,
- labels=None):
+ def start_case(self, name, description=None, labels=None):
"""
Starts a new :py:class:`allure.structure.TestCase`
"""
test = TestCase(name=name,
description=description,
- severity=severity,
start=now(),
attachments=[],
labels=labels or [],
@@ -187,9 +185,7 @@ def _save_attach(self, body, attach_type=AttachmentType.TEXT):
:arg body: str or unicode with contents. str is written as-is in byte stream, unicode is written as utf-8 (what do you expect else?)
"""
-
- # FIXME: we should generate attachment name properly
- with self._attachfile("%s-attachment.%s" % (uuid.uuid4(), attach_type)) as f:
+ with self._attachfile("%s-attachment.%s" % (uuid.uuid4(), attach_type.extension)) as f:
if isinstance(body, unicode):
f.write(body.encode('utf-8'))
else:
@@ -214,7 +210,7 @@ def _reportfile(self, filename):
reportpath = os.path.join(self.logdir, filename)
encoding = 'utf-8'
- logfile = py.std.codecs.open(reportpath, 'w', encoding=encoding) # @UndefinedVariable
+ logfile = py.std.codecs.open(reportpath, 'w', encoding=encoding)
try:
yield logfile
diff --git a/allure/constants.py b/allure/constants.py
index faf2979..5147b6c 100644
--- a/allure/constants.py
+++ b/allure/constants.py
@@ -5,40 +5,46 @@
@author: pupssman
'''
-
-
-class Severity:
- BLOCKER = 'blocker'
- CRITICAL = 'critical'
- NORMAL = 'normal'
- MINOR = 'minor'
- TRIVIAL = 'trivial'
+from enum import Enum
class Status:
FAILED = 'failed'
BROKEN = 'broken'
PASSED = 'passed'
- SKIPPED = 'skipped'
+ SKIPPED = 'canceled'
+ CANCELED = 'canceled'
+ PENDING = 'pending'
-FAILED_STATUSES = [Status.FAILED, Status.BROKEN]
+class Label:
+ DEFAULT = 'allure_label'
+ FEATURE = 'feature'
+ STORY = 'story'
+ SEVERITY = 'severity'
-class AttachmentType:
- TEXT = "txt"
- HTML = "html"
- XML = "xml"
- PNG = "png"
- JPG = "jpg"
- JSON = "json"
- OTHER = "other"
+class Severity:
+ BLOCKER = 'blocker'
+ CRITICAL = 'critical'
+ NORMAL = 'normal'
+ MINOR = 'minor'
+ TRIVIAL = 'trivial'
-ALLURE_NAMESPACE = "urn:model.allure.qatools.yandex.ru"
+class AttachmentType(Enum):
+ def __init__(self, mime_type, extension):
+ self.mime_type = mime_type
+ self.extension = extension
+ TEXT = ("text/plain", "txt")
+ HTML = ("application/html", "html")
+ XML = ("application/xml", "xml")
+ PNG = ("image/png", "png")
+ JPG = ("image/jpg", "jpg")
+ JSON = ("application/json", "json")
+ OTHER = ("other", "other")
-class Label:
- DEFAULT = 'allure_label'
- FEATURE = 'feature'
- STORY = 'story'
+
+ALLURE_NAMESPACE = "urn:model.allure.qatools.yandex.ru"
+FAILED_STATUSES = [Status.FAILED, Status.BROKEN]
diff --git a/allure/pytest_plugin.py b/allure/pytest_plugin.py
index ff62e04..185ec7a 100644
--- a/allure/pytest_plugin.py
+++ b/allure/pytest_plugin.py
@@ -8,8 +8,8 @@
from allure.utils import LabelsList
from allure.constants import Status, AttachmentType, Severity, \
FAILED_STATUSES, Label
-from allure.utils import parent_module, parent_down_from_module, severity_of, \
- labels_of, all_of, get_exception_message
+from allure.utils import parent_module, parent_down_from_module, labels_of, \
+ all_of, get_exception_message
from allure.structure import TestLabel
@@ -23,12 +23,12 @@ def pytest_addoption(parser):
severities = [v for (_, v) in all_of(Severity)]
- def severity_type(string):
- entries = [x.strip() for x in string.split(',')]
+ def severity_label_type(string):
+ entries = LabelsList([TestLabel(name=Label.SEVERITY, value=x) for x in string.split(',')])
for entry in entries:
- if entry not in severities:
- raise argparse.ArgumentTypeError('Illegal severity value [%s], only values from [%s] are allowed.' % (entry, ', '.join(severities)))
+ if entry.value not in severities:
+ raise argparse.ArgumentTypeError('Illegal severity value [%s], only values from [%s] are allowed.' % (entry.value, ', '.join(severities)))
return entries
@@ -42,8 +42,8 @@ def stories_label_type(string):
action="store",
dest="allureseverities",
metavar="SEVERITIES_LIST",
- default=None,
- type=severity_type,
+ default=LabelsList(),
+ type=severity_label_type,
help="""Comma-separated list of severity names.
Tests only with these severities will be run.
Possible values are:%s.""" % ', '.join(severities))
@@ -77,15 +77,10 @@ def pytest_configure(config):
def pytest_runtest_setup(item):
- severity = severity_of(item)
item_labels = labels_of(item)
option = item.config.option
- if option.allureseverities and severity not in \
- option.allureseverities:
- pytest.skip("Not running test of severity %s." % severity)
-
- arg_labels = option.allurefeatures + option.allurestories
+ arg_labels = option.allurefeatures + option.allurestories + option.allureseverities
if arg_labels and not item_labels & arg_labels:
pytest.skip('Not suitable with selected labels: %s.' % arg_labels)
@@ -123,12 +118,6 @@ def attach(self, name, contents, type=AttachmentType.TEXT): # @ReservedAssignme
if self._allurelistener:
self._allurelistener.attach(name, contents, type)
- def severity(self, level):
- """
- A decorator factory that returns ``pytest.mark`` for a given allure ``level``.
- """
- return pytest.mark.allure_severity(level)
-
def label(self, name, *value):
"""
A decorator factory that returns ``pytest.mark`` for a given label.
@@ -138,6 +127,12 @@ def label(self, name, *value):
(Label.DEFAULT, name.encode('utf-8', 'ignore')))
return allure_label(*value)
+ def severity(self, severity):
+ """
+ A decorator factory that returns ``pytest.mark`` for a given allure ``level``.
+ """
+ return self.label(Label.SEVERITY, severity)
+
def feature(self, *features):
"""
A decorator factory that returns ``pytest.mark`` for a given features.
@@ -277,8 +272,7 @@ def pytest_runtest_protocol(self, __multicall__, item, nextitem):
self.testsuite = 'Yes'
name = '.'.join(mangle_testnames([x.name for x in parent_down_from_module(item)]))
- self.impl.start_case(name, description=item.function.__doc__, severity=severity_of(item),
- labels=labels_of(item))
+ self.impl.start_case(name, description=item.function.__doc__, labels=labels_of(item))
result = __multicall__.execute()
if not nextitem or parent_module(item) != parent_module(nextitem):
diff --git a/allure/structure.py b/allure/structure.py
index d6d58f4..02290e7 100644
--- a/allure/structure.py
+++ b/allure/structure.py
@@ -31,8 +31,7 @@
labels=Many(Nested()),
status=Attribute(),
start=Attribute(),
- stop=Attribute(),
- severity=Attribute())
+ stop=Attribute())
TestSuite = xmlfied('test-suite',
diff --git a/allure/utils.py b/allure/utils.py
index 1c3a3da..1e4478b 100644
--- a/allure/utils.py
+++ b/allure/utils.py
@@ -15,7 +15,7 @@
from _pytest.python import Module
-from allure.constants import Severity, Label
+from allure.constants import Label
from allure.structure import TestLabel
@@ -60,14 +60,6 @@ def now():
return sec2ms(time.time())
-def severity_of(item):
- severity_marker = item.get_marker('allure_severity')
- if severity_marker:
- return severity_marker.args[0]
- else:
- return Severity.NORMAL
-
-
def labels_of(item):
"""
Returns list of TestLabel elements.
diff --git a/setup.py b/setup.py
index 7ea4339..9343f8c 100644
--- a/setup.py
+++ b/setup.py
@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
PACKAGE = "pytest-allure-adaptor"
-VERSION = "1.4.1"
+VERSION = "1.5.0"
import os
from setuptools import setup
@@ -24,5 +24,6 @@ def read(fname):
install_requires=[
"lxml>=3.2.0",
"pytest>=2.4.1",
- "recordtype"]
+ "recordtype",
+ "enum34"]
)
diff --git a/tests/allure.xsd b/tests/allure.xsd
index cf3d55b..75f31aa 100644
--- a/tests/allure.xsd
+++ b/tests/allure.xsd
@@ -1,165 +1,173 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/conftest.py b/tests/conftest.py
index 34a8e45..c8a920f 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -3,15 +3,13 @@
from lxml import etree, objectify
-from hamcrest.core.helpers.wrap_matcher import wrap_matcher
-from hamcrest.core.base_matcher import BaseMatcher
-
pytest_plugins = ["pytester"]
@pytest.fixture
def schema():
"""
+ schema copied from https://github.com/allure-framework/allure-core/blob/allure-core-1.4.1/allure-model/src/main/resources/allure.xsd
Returns :py:class:`lxml.etree.XMLSchema` object configured with schema for reports
"""
path_to_schema = os.path.join(os.path.dirname(__file__), 'allure.xsd')
@@ -57,20 +55,3 @@ def impl(*a, **kw):
return reports[0]
return impl
-
-
-class HasFloat(BaseMatcher):
-
- def __init__(self, str_matcher):
- self.str_matcher = str_matcher
-
- def _matches(self, item):
- return self.str_matcher.matches(float(item))
-
- def describe_to(self, description):
- description.append_text('an object with float ') \
- .append_description_of(self.str_matcher)
-
-
-def has_float(match):
- return HasFloat(wrap_matcher(match))
diff --git a/tests/matchers.py b/tests/matchers.py
new file mode 100644
index 0000000..7b3b483
--- /dev/null
+++ b/tests/matchers.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+__author__ = 'mavlyutov@yandex-team.ru'
+
+from hamcrest.core.helpers.wrap_matcher import wrap_matcher
+from hamcrest.core.base_matcher import BaseMatcher
+from hamcrest import equal_to, has_property, has_properties, has_item, anything
+
+
+class HasFloat(BaseMatcher):
+
+ def __init__(self, str_matcher):
+ self.str_matcher = str_matcher
+
+ def _matches(self, item):
+ return self.str_matcher.matches(float(item))
+
+ def describe_to(self, description):
+ description.append_text('an object with float ') \
+ .append_description_of(self.str_matcher)
+
+
+def has_float(match):
+ return HasFloat(wrap_matcher(match))
+
+
+def has_label(test_name, label_name=anything(), label_value=anything()):
+ return has_property('{}test-cases',
+ has_property('test-case',
+ has_item(
+ has_properties({'name': equal_to(test_name),
+ 'labels': has_property('label',
+ has_item(
+ has_property('attrib', equal_to(
+ {'name': label_name,
+ 'value': label_value}))))}))))
diff --git a/tests/test_attach.py b/tests/test_attach.py
index 26281d0..d5083e2 100644
--- a/tests/test_attach.py
+++ b/tests/test_attach.py
@@ -36,7 +36,7 @@ def test_x():
A.attach('Foo', 'Bar', A.attach_type.%s)
""" % a_type)
- assert_that(report.find('.//attachment').attrib, has_entries(title='Foo', type=getattr(AttachmentType, a_type)))
+ assert_that(report.find('.//attachment').attrib, has_entries(title='Foo', type=getattr(AttachmentType, a_type).mime_type))
class TestContents:
diff --git a/tests/test_labels.py b/tests/test_labels.py
index ae72f2b..a2bceb3 100644
--- a/tests/test_labels.py
+++ b/tests/test_labels.py
@@ -7,21 +7,10 @@
"""
import pytest
+from matchers import has_label
from hamcrest import assert_that, equal_to, has_length, is_not, has_property, has_properties, has_item, anything, all_of, any_of
-def has_label(test_name, label_name=anything(), label_value=anything()):
- return has_property('{}test-cases',
- has_property('test-case',
- has_item(
- has_properties({'name': equal_to(test_name),
- 'labels': has_property('label',
- has_item(
- has_property('attrib', equal_to(
- {'name': label_name,
- 'value': label_value}))))}))))
-
-
def has_label_length(test_name, label_length):
return has_property('{}test-cases',
has_property('test-case',
diff --git a/tests/test_severity.py b/tests/test_severity.py
index bcf613a..d7d949e 100644
--- a/tests/test_severity.py
+++ b/tests/test_severity.py
@@ -6,12 +6,23 @@
@author: pupssman
"""
-from hamcrest import assert_that, contains, all_of, has_entry, has_property
+from hamcrest import assert_that, contains, all_of, has_entry, has_property, has_properties, contains_inanyorder, has_item, equal_to
from allure.constants import Severity, Status
from allure import utils
+from matchers import has_label
import pytest
+def severity_element(value):
+ return has_properties(attrib=all_of(
+ has_entry('name', 'severity'),
+ has_entry('value', value)))
+
+
+def has_test_with_severity(test_name, severity_level):
+ return has_label(test_name, label_value=severity_level, label_name='severity')
+
+
@pytest.mark.parametrize('mark_way', [
'@pytest.allure.%s',
'@pytest.allure.severity(pytest.allure.severity_level.%s)'
@@ -26,7 +37,7 @@ def test_foo():
pass
""" % (mark_way % name))
- assert_that(report.xpath(".//test-case/@severity"), contains(value))
+ assert_that(report.findall(".//test-case/labels/label"), contains(severity_element(value)))
def test_class_severity(report_for):
@@ -47,7 +58,11 @@ def test_b(self):
pass
""")
- assert_that(report.xpath(".//test-case/@severity"), contains(Severity.CRITICAL, Severity.TRIVIAL))
+ assert_that(report, all_of(
+ has_test_with_severity('TestMy.test_a', Severity.CRITICAL),
+ has_test_with_severity('TestMy.test_b', Severity.TRIVIAL),
+ has_test_with_severity('TestMy.test_b', Severity.CRITICAL)
+ ))
def test_module_severity(report_for):
@@ -77,7 +92,16 @@ def test_b(self):
pass
""")
- assert_that(report.xpath(".//test-case/@severity"), contains(Severity.MINOR, Severity.NORMAL, Severity.CRITICAL, Severity.TRIVIAL))
+ assert_that(report, all_of(
+ has_test_with_severity('test_m', Severity.MINOR),
+ has_test_with_severity('test_n', Severity.MINOR),
+ has_test_with_severity('test_n', Severity.NORMAL),
+ has_test_with_severity('TestMy.test_a', Severity.MINOR),
+ has_test_with_severity('TestMy.test_a', Severity.CRITICAL),
+ has_test_with_severity('TestMy.test_b', Severity.MINOR),
+ has_test_with_severity('TestMy.test_b', Severity.CRITICAL),
+ has_test_with_severity('TestMy.test_b', Severity.TRIVIAL)
+ ))
@pytest.mark.parametrize('severities', [
@@ -98,19 +122,18 @@ def test_run_only(report_for, severities):
def test_a():
pass
+ @pytest.allure.MINOR
def test_b():
pass
- @pytest.allure.MINOR
def test_c():
pass
""", extra_run_args=['--allure_severities', ','.join(severities)])
- a_status, b_status, c_status = [Status.PASSED if s in severities else Status.SKIPPED for s in [Severity.CRITICAL, Severity.NORMAL, Severity.MINOR]]
+ a_status, b_status, c_status = [Status.PASSED if s in severities else Status.SKIPPED for s in [Severity.CRITICAL, Severity.MINOR, '']]
- assert_that(report.xpath(".//test-case"), contains(all_of(has_property('name', 'test_a'),
- has_property('attrib', has_entry('status', a_status))),
- all_of(has_property('name', 'test_b'),
- has_property('attrib', has_entry('status', b_status))),
- all_of(has_property('name', 'test_c'),
- has_property('attrib', has_entry('status', c_status)))))
+ assert_that(report.xpath(".//test-case"), contains(
+ all_of(has_property('name', 'test_a'), has_property('attrib', has_entry('status', a_status))),
+ all_of(has_property('name', 'test_b'), has_property('attrib', has_entry('status', b_status))),
+ all_of(has_property('name', 'test_c'), has_property('attrib', has_entry('status', c_status)))
+ ))
diff --git a/tests/test_smoke.py b/tests/test_smoke.py
index b2c366e..27409ac 100644
--- a/tests/test_smoke.py
+++ b/tests/test_smoke.py
@@ -10,10 +10,10 @@
import time
import pytest
-from hamcrest import is_, assert_that, contains, has_property, all_of, has_entry, greater_than, less_than, has_entries, contains_inanyorder, is_not, has_items, starts_with
+from hamcrest import is_, assert_that, contains, has_property, all_of, has_entry, greater_than, less_than, \
+ has_entries, contains_inanyorder, is_not, has_items, starts_with
from allure.constants import Status
-
-from conftest import has_float
+from matchers import has_float
@pytest.mark.parametrize('statement', ['assert 1', 'assert 0',
diff --git a/tests/test_steps.py b/tests/test_steps.py
index c5b6133..25fada9 100644
--- a/tests/test_steps.py
+++ b/tests/test_steps.py
@@ -12,7 +12,7 @@
from hamcrest.library.number.ordering_comparison import greater_than_or_equal_to, \
less_than_or_equal_to
from hamcrest.core.core.allof import all_of
-from tests.conftest import has_float
+from matchers import has_float
from allure.constants import Status
import pytest