test_ok1/testing/test_mark.py

929 lines
28 KiB
Python
Raw Normal View History

from __future__ import absolute_import, division, print_function
import os
import sys
import pytest
from _pytest.mark import (
MarkGenerator as Mark, ParameterSet, transfer_markers,
EMPTY_PARAMETERSET_OPTION,
)
ignore_markinfo = pytest.mark.filterwarnings('ignore:MarkInfo objects:_pytest.deprecated.RemovedInPytest4Warning')
class TestMark(object):
def test_markinfo_repr(self):
from _pytest.mark import MarkInfo, Mark
m = MarkInfo(Mark("hello", (1, 2), {}))
repr(m)
@pytest.mark.parametrize('attr', ['mark', 'param'])
@pytest.mark.parametrize('modulename', ['py.test', 'pytest'])
def test_pytest_exists_in_namespace_all(self, attr, modulename):
module = sys.modules[modulename]
assert attr in module.__all__
def test_pytest_mark_notcallable(self):
mark = Mark()
pytest.raises((AttributeError, TypeError), mark)
2017-07-21 13:26:56 +08:00
def test_mark_with_param(self):
def some_function(abc):
pass
class SomeClass(object):
pass
assert pytest.mark.fun(some_function) is some_function
assert pytest.mark.fun.with_args(some_function) is not some_function
assert pytest.mark.fun(SomeClass) is SomeClass
assert pytest.mark.fun.with_args(SomeClass) is not SomeClass
def test_pytest_mark_name_starts_with_underscore(self):
mark = Mark()
pytest.raises(AttributeError, getattr, mark, '_some_name')
def test_pytest_mark_bare(self):
mark = Mark()
def f():
pass
mark.hello(f)
assert f.hello
@ignore_markinfo
def test_pytest_mark_keywords(self):
mark = Mark()
def f():
pass
mark.world(x=3, y=4)(f)
assert f.world
assert f.world.kwargs['x'] == 3
assert f.world.kwargs['y'] == 4
@ignore_markinfo
def test_apply_multiple_and_merge(self):
mark = Mark()
def f():
pass
mark.world
mark.world(x=3)(f)
assert f.world.kwargs['x'] == 3
mark.world(y=4)(f)
assert f.world.kwargs['x'] == 3
assert f.world.kwargs['y'] == 4
mark.world(y=1)(f)
assert f.world.kwargs['y'] == 1
assert len(f.world.args) == 0
@ignore_markinfo
def test_pytest_mark_positional(self):
mark = Mark()
def f():
pass
mark.world("hello")(f)
assert f.world.args[0] == "hello"
mark.world("world")(f)
@ignore_markinfo
fix handling MarkDecorators called with a single positional plus keyword args When a MarkDecorator instance is called it does the following: 1. If called with a single class as its only positional argument and no additional keyword arguments, it attaches itself to the class so it gets applied automatically to all test cases found in that class. 2. If called with a single function as its only positional argument and no additional keyword arguments, it attaches a MarkInfo object to the function, containing all the arguments already stored internally in the MarkDecorator. 3. When called in any other case, it performs a 'fake construction' call, i.e. it returns a new MarkDecorator instance with the original MarkDecorator's content updated with the arguments passed to this call. When Python applies a function decorator it always passes the target class/ function to the decorator as its positional argument with no additional positional or keyword arguments. However, when MarkDecorator was deciding whether it was being called to decorate a target function/class (cases 1. & 2. as documented above) or to return an updated MarkDecorator (case 3. as documented above), it only checked that it received a single callable positional argument and did not take into consideration whether additional keyword arguments were being passed in as well. With this change, it is now possible to create a pytest mark storing a function/ class parameter passed as its only positional argument and accompanied by one or more additional keyword arguments. Before, it was only possible to do so if the function/class parameter argument was accompanied by at least one other positional argument. Added a related unit test. Updated MarkDecorator doc-string.
2014-01-20 08:27:33 +08:00
def test_pytest_mark_positional_func_and_keyword(self):
mark = Mark()
fix handling MarkDecorators called with a single positional plus keyword args When a MarkDecorator instance is called it does the following: 1. If called with a single class as its only positional argument and no additional keyword arguments, it attaches itself to the class so it gets applied automatically to all test cases found in that class. 2. If called with a single function as its only positional argument and no additional keyword arguments, it attaches a MarkInfo object to the function, containing all the arguments already stored internally in the MarkDecorator. 3. When called in any other case, it performs a 'fake construction' call, i.e. it returns a new MarkDecorator instance with the original MarkDecorator's content updated with the arguments passed to this call. When Python applies a function decorator it always passes the target class/ function to the decorator as its positional argument with no additional positional or keyword arguments. However, when MarkDecorator was deciding whether it was being called to decorate a target function/class (cases 1. & 2. as documented above) or to return an updated MarkDecorator (case 3. as documented above), it only checked that it received a single callable positional argument and did not take into consideration whether additional keyword arguments were being passed in as well. With this change, it is now possible to create a pytest mark storing a function/ class parameter passed as its only positional argument and accompanied by one or more additional keyword arguments. Before, it was only possible to do so if the function/class parameter argument was accompanied by at least one other positional argument. Added a related unit test. Updated MarkDecorator doc-string.
2014-01-20 08:27:33 +08:00
def f():
raise Exception
fix handling MarkDecorators called with a single positional plus keyword args When a MarkDecorator instance is called it does the following: 1. If called with a single class as its only positional argument and no additional keyword arguments, it attaches itself to the class so it gets applied automatically to all test cases found in that class. 2. If called with a single function as its only positional argument and no additional keyword arguments, it attaches a MarkInfo object to the function, containing all the arguments already stored internally in the MarkDecorator. 3. When called in any other case, it performs a 'fake construction' call, i.e. it returns a new MarkDecorator instance with the original MarkDecorator's content updated with the arguments passed to this call. When Python applies a function decorator it always passes the target class/ function to the decorator as its positional argument with no additional positional or keyword arguments. However, when MarkDecorator was deciding whether it was being called to decorate a target function/class (cases 1. & 2. as documented above) or to return an updated MarkDecorator (case 3. as documented above), it only checked that it received a single callable positional argument and did not take into consideration whether additional keyword arguments were being passed in as well. With this change, it is now possible to create a pytest mark storing a function/ class parameter passed as its only positional argument and accompanied by one or more additional keyword arguments. Before, it was only possible to do so if the function/class parameter argument was accompanied by at least one other positional argument. Added a related unit test. Updated MarkDecorator doc-string.
2014-01-20 08:27:33 +08:00
m = mark.world(f, omega="hello")
fix handling MarkDecorators called with a single positional plus keyword args When a MarkDecorator instance is called it does the following: 1. If called with a single class as its only positional argument and no additional keyword arguments, it attaches itself to the class so it gets applied automatically to all test cases found in that class. 2. If called with a single function as its only positional argument and no additional keyword arguments, it attaches a MarkInfo object to the function, containing all the arguments already stored internally in the MarkDecorator. 3. When called in any other case, it performs a 'fake construction' call, i.e. it returns a new MarkDecorator instance with the original MarkDecorator's content updated with the arguments passed to this call. When Python applies a function decorator it always passes the target class/ function to the decorator as its positional argument with no additional positional or keyword arguments. However, when MarkDecorator was deciding whether it was being called to decorate a target function/class (cases 1. & 2. as documented above) or to return an updated MarkDecorator (case 3. as documented above), it only checked that it received a single callable positional argument and did not take into consideration whether additional keyword arguments were being passed in as well. With this change, it is now possible to create a pytest mark storing a function/ class parameter passed as its only positional argument and accompanied by one or more additional keyword arguments. Before, it was only possible to do so if the function/class parameter argument was accompanied by at least one other positional argument. Added a related unit test. Updated MarkDecorator doc-string.
2014-01-20 08:27:33 +08:00
def g():
pass
fix handling MarkDecorators called with a single positional plus keyword args When a MarkDecorator instance is called it does the following: 1. If called with a single class as its only positional argument and no additional keyword arguments, it attaches itself to the class so it gets applied automatically to all test cases found in that class. 2. If called with a single function as its only positional argument and no additional keyword arguments, it attaches a MarkInfo object to the function, containing all the arguments already stored internally in the MarkDecorator. 3. When called in any other case, it performs a 'fake construction' call, i.e. it returns a new MarkDecorator instance with the original MarkDecorator's content updated with the arguments passed to this call. When Python applies a function decorator it always passes the target class/ function to the decorator as its positional argument with no additional positional or keyword arguments. However, when MarkDecorator was deciding whether it was being called to decorate a target function/class (cases 1. & 2. as documented above) or to return an updated MarkDecorator (case 3. as documented above), it only checked that it received a single callable positional argument and did not take into consideration whether additional keyword arguments were being passed in as well. With this change, it is now possible to create a pytest mark storing a function/ class parameter passed as its only positional argument and accompanied by one or more additional keyword arguments. Before, it was only possible to do so if the function/class parameter argument was accompanied by at least one other positional argument. Added a related unit test. Updated MarkDecorator doc-string.
2014-01-20 08:27:33 +08:00
assert m(g) == g
assert g.world.args[0] is f
assert g.world.kwargs["omega"] == "hello"
@ignore_markinfo
def test_pytest_mark_reuse(self):
mark = Mark()
def f():
pass
w = mark.some
w("hello", reason="123")(f)
assert f.some.args[0] == "hello"
assert f.some.kwargs['reason'] == "123"
def g():
pass
w("world", reason2="456")(g)
assert g.some.args[0] == "world"
assert 'reason' not in g.some.kwargs
assert g.some.kwargs['reason2'] == "456"
def test_marked_class_run_twice(testdir, request):
"""Test fails file is run twice that contains marked class.
See issue#683.
"""
py_file = testdir.makepyfile("""
import pytest
@pytest.mark.parametrize('abc', [1, 2, 3])
class Test1(object):
def test_1(self, abc):
assert abc in [1, 2, 3]
""")
file_name = os.path.basename(py_file.strpath)
rec = testdir.inline_run(file_name, file_name)
rec.assertoutcome(passed=6)
def test_ini_markers(testdir):
testdir.makeini("""
[pytest]
markers =
a1: this is a webtest marker
a2: this is a smoke marker
""")
testdir.makepyfile("""
def test_markers(pytestconfig):
markers = pytestconfig.getini("markers")
print (markers)
assert len(markers) >= 2
assert markers[0].startswith("a1:")
assert markers[1].startswith("a2:")
""")
rec = testdir.inline_run()
rec.assertoutcome(passed=1)
def test_markers_option(testdir):
testdir.makeini("""
[pytest]
markers =
a1: this is a webtest marker
a1some: another marker
2017-11-22 20:47:15 +08:00
nodescription
""")
result = testdir.runpytest("--markers", )
result.stdout.fnmatch_lines([
"*a1*this is a webtest*",
"*a1some*another marker",
2017-11-22 20:47:15 +08:00
"*nodescription*",
])
def test_ini_markers_whitespace(testdir):
testdir.makeini("""
[pytest]
markers =
a1 : this is a whitespace marker
""")
testdir.makepyfile("""
import pytest
@pytest.mark.a1
def test_markers():
assert True
""")
rec = testdir.inline_run("--strict", "-m", "a1")
rec.assertoutcome(passed=1)
2017-11-22 20:47:15 +08:00
def test_marker_without_description(testdir):
testdir.makefile(".cfg", setup="""
[tool:pytest]
markers=slow
""")
testdir.makeconftest("""
import pytest
pytest.mark.xfail('FAIL')
""")
ftdir = testdir.mkdir("ft1_dummy")
testdir.tmpdir.join("conftest.py").move(ftdir.join("conftest.py"))
rec = testdir.runpytest_subprocess("--strict")
rec.assert_outcomes()
def test_markers_option_with_plugin_in_current_dir(testdir):
testdir.makeconftest('pytest_plugins = "flip_flop"')
testdir.makepyfile(flip_flop="""\
def pytest_configure(config):
config.addinivalue_line("markers", "flip:flop")
def pytest_generate_tests(metafunc):
try:
mark = metafunc.function.flipper
except AttributeError:
return
metafunc.parametrize("x", (10, 20))""")
testdir.makepyfile("""\
import pytest
@pytest.mark.flipper
def test_example(x):
assert x""")
result = testdir.runpytest("--markers")
result.stdout.fnmatch_lines(["*flip*flop*"])
def test_mark_on_pseudo_function(testdir):
testdir.makepyfile("""
import pytest
@pytest.mark.r(lambda x: 0/0)
def test_hello():
pass
""")
reprec = testdir.inline_run()
reprec.assertoutcome(passed=1)
def test_strict_prohibits_unregistered_markers(testdir):
testdir.makepyfile("""
import pytest
@pytest.mark.unregisteredmark
def test_hello():
pass
""")
result = testdir.runpytest("--strict")
assert result.ret != 0
result.stdout.fnmatch_lines([
"*unregisteredmark*not*registered*",
])
@pytest.mark.parametrize("spec", [
("xyz", ("test_one",)),
("xyz and xyz2", ()),
("xyz2", ("test_two",)),
("xyz or xyz2", ("test_one", "test_two"),)
])
def test_mark_option(spec, testdir):
testdir.makepyfile("""
import pytest
@pytest.mark.xyz
def test_one():
pass
@pytest.mark.xyz2
def test_two():
pass
""")
opt, passed_result = spec
rec = testdir.inline_run("-m", opt)
passed, skipped, fail = rec.listoutcomes()
passed = [x.nodeid.split("::")[-1] for x in passed]
assert len(passed) == len(passed_result)
assert list(passed) == list(passed_result)
@pytest.mark.parametrize("spec", [
("interface", ("test_interface",)),
("not interface", ("test_nointer",)),
])
def test_mark_option_custom(spec, testdir):
testdir.makeconftest("""
import pytest
def pytest_collection_modifyitems(items):
for item in items:
if "interface" in item.nodeid:
item.keywords["interface"] = pytest.mark.interface
""")
testdir.makepyfile("""
def test_interface():
pass
def test_nointer():
pass
""")
opt, passed_result = spec
rec = testdir.inline_run("-m", opt)
passed, skipped, fail = rec.listoutcomes()
passed = [x.nodeid.split("::")[-1] for x in passed]
assert len(passed) == len(passed_result)
assert list(passed) == list(passed_result)
@pytest.mark.parametrize("spec", [
("interface", ("test_interface",)),
("not interface", ("test_nointer", "test_pass")),
("pass", ("test_pass",)),
("not pass", ("test_interface", "test_nointer")),
])
def test_keyword_option_custom(spec, testdir):
testdir.makepyfile("""
def test_interface():
pass
def test_nointer():
pass
def test_pass():
pass
""")
opt, passed_result = spec
rec = testdir.inline_run("-k", opt)
passed, skipped, fail = rec.listoutcomes()
passed = [x.nodeid.split("::")[-1] for x in passed]
assert len(passed) == len(passed_result)
assert list(passed) == list(passed_result)
@pytest.mark.parametrize("spec", [
("None", ("test_func[None]",)),
("1.3", ("test_func[1.3]",)),
("2-3", ("test_func[2-3]",))
])
def test_keyword_option_parametrize(spec, testdir):
testdir.makepyfile("""
import pytest
@pytest.mark.parametrize("arg", [None, 1.3, "2-3"])
def test_func(arg):
pass
""")
opt, passed_result = spec
rec = testdir.inline_run("-k", opt)
passed, skipped, fail = rec.listoutcomes()
passed = [x.nodeid.split("::")[-1] for x in passed]
assert len(passed) == len(passed_result)
assert list(passed) == list(passed_result)
@pytest.mark.parametrize("spec", [
2018-01-17 04:35:57 +08:00
("foo or import", "ERROR: Python keyword 'import' not accepted in expressions passed to '-k'"),
("foo or", "ERROR: Wrong expression passed to '-k': foo or")
])
def test_keyword_option_wrong_arguments(spec, testdir, capsys):
testdir.makepyfile("""
def test_func(arg):
pass
""")
opt, expected_result = spec
testdir.inline_run("-k", opt)
2018-01-17 04:35:57 +08:00
out = capsys.readouterr().err
assert expected_result in out
def test_parametrized_collected_from_command_line(testdir):
"""Parametrized test not collected if test named specified
in command line issue#649.
"""
py_file = testdir.makepyfile("""
import pytest
@pytest.mark.parametrize("arg", [None, 1.3, "2-3"])
def test_func(arg):
pass
""")
file_name = os.path.basename(py_file.strpath)
rec = testdir.inline_run(file_name + "::" + "test_func")
rec.assertoutcome(passed=3)
def test_parametrized_collect_with_wrong_args(testdir):
"""Test collect parametrized func with wrong number of args."""
py_file = testdir.makepyfile("""
import pytest
@pytest.mark.parametrize('foo, bar', [(1, 2, 3)])
def test_func(foo, bar):
pass
""")
result = testdir.runpytest(py_file)
result.stdout.fnmatch_lines([
'E ValueError: In "parametrize" the number of values ((1, 2, 3)) '
'must be equal to the number of names ([\'foo\', \'bar\'])'
])
2017-10-09 00:02:54 +08:00
def test_parametrized_with_kwargs(testdir):
"""Test collect parametrized func with wrong number of args."""
py_file = testdir.makepyfile("""
import pytest
@pytest.fixture(params=[1,2])
def a(request):
return request.param
@pytest.mark.parametrize(argnames='b', argvalues=[1, 2])
def test_func(a, b):
pass
""")
result = testdir.runpytest(py_file)
assert(result.ret == 0)
class TestFunctional(object):
def test_mark_per_function(self, testdir):
p = testdir.makepyfile("""
import pytest
@pytest.mark.hello
def test_hello():
assert hasattr(test_hello, 'hello')
""")
result = testdir.runpytest(p)
result.stdout.fnmatch_lines(["*1 passed*"])
def test_mark_per_module(self, testdir):
item = testdir.getitem("""
import pytest
pytestmark = pytest.mark.hello
def test_func():
pass
""")
keywords = item.keywords
assert 'hello' in keywords
def test_marklist_per_class(self, testdir):
item = testdir.getitem("""
import pytest
class TestClass(object):
pytestmark = [pytest.mark.hello, pytest.mark.world]
def test_func(self):
assert TestClass.test_func.hello
assert TestClass.test_func.world
""")
keywords = item.keywords
assert 'hello' in keywords
def test_marklist_per_module(self, testdir):
item = testdir.getitem("""
import pytest
pytestmark = [pytest.mark.hello, pytest.mark.world]
class TestClass(object):
def test_func(self):
assert TestClass.test_func.hello
assert TestClass.test_func.world
""")
keywords = item.keywords
assert 'hello' in keywords
assert 'world' in keywords
def test_mark_per_class_decorator(self, testdir):
item = testdir.getitem("""
import pytest
@pytest.mark.hello
class TestClass(object):
def test_func(self):
assert TestClass.test_func.hello
""")
keywords = item.keywords
assert 'hello' in keywords
def test_mark_per_class_decorator_plus_existing_dec(self, testdir):
item = testdir.getitem("""
import pytest
@pytest.mark.hello
class TestClass(object):
pytestmark = pytest.mark.world
def test_func(self):
assert TestClass.test_func.hello
assert TestClass.test_func.world
""")
keywords = item.keywords
assert 'hello' in keywords
assert 'world' in keywords
@ignore_markinfo
def test_merging_markers(self, testdir):
p = testdir.makepyfile("""
import pytest
pytestmark = pytest.mark.hello("pos1", x=1, y=2)
class TestClass(object):
# classlevel overrides module level
pytestmark = pytest.mark.hello(x=3)
@pytest.mark.hello("pos0", z=4)
def test_func(self):
pass
""")
items, rec = testdir.inline_genitems(p)
item, = items
keywords = item.keywords
marker = keywords['hello']
assert marker.args == ("pos0", "pos1")
assert marker.kwargs == {'x': 1, 'y': 2, 'z': 4}
# test the new __iter__ interface
values = list(marker)
assert len(values) == 3
assert values[0].args == ("pos0",)
assert values[1].args == ()
assert values[2].args == ("pos1", )
2012-11-06 04:52:12 +08:00
def test_merging_markers_deep(self, testdir):
# issue 199 - propagate markers into nested classes
p = testdir.makepyfile("""
import pytest
class TestA(object):
2012-11-06 04:52:12 +08:00
pytestmark = pytest.mark.a
def test_b(self):
assert True
class TestC(object):
2012-11-06 04:52:12 +08:00
# this one didnt get marked
def test_d(self):
assert True
""")
items, rec = testdir.inline_genitems(p)
for item in items:
print(item, item.keywords)
assert list(item.find_markers('a'))
2012-11-06 04:52:12 +08:00
def test_mark_decorator_subclass_does_not_propagate_to_base(self, testdir):
p = testdir.makepyfile("""
import pytest
@pytest.mark.a
class Base(object): pass
@pytest.mark.b
class Test1(Base):
def test_foo(self): pass
class Test2(Base):
def test_bar(self): pass
""")
items, rec = testdir.inline_genitems(p)
self.assert_markers(items, test_foo=('a', 'b'), test_bar=('a',))
2016-06-25 17:10:23 +08:00
@pytest.mark.issue568
@pytest.mark.xfail(reason="markers smear on methods of base classes")
def test_mark_should_not_pass_to_siebling_class(self, testdir):
2016-06-25 17:10:23 +08:00
p = testdir.makepyfile("""
import pytest
class TestBase(object):
2016-06-25 17:10:23 +08:00
def test_foo(self):
pass
@pytest.mark.b
class TestSub(TestBase):
pass
class TestOtherSub(TestBase):
pass
""")
items, rec = testdir.inline_genitems(p)
base_item, sub_item, sub_item_other = items
assert not hasattr(base_item.obj, 'b')
assert not hasattr(sub_item_other.obj, 'b')
def test_mark_decorator_baseclasses_merged(self, testdir):
p = testdir.makepyfile("""
import pytest
@pytest.mark.a
class Base(object): pass
@pytest.mark.b
class Base2(Base): pass
@pytest.mark.c
class Test1(Base2):
def test_foo(self): pass
class Test2(Base2):
@pytest.mark.d
def test_bar(self): pass
""")
items, rec = testdir.inline_genitems(p)
self.assert_markers(items, test_foo=('a', 'b', 'c'),
test_bar=('a', 'b', 'd'))
def test_mark_with_wrong_marker(self, testdir):
reprec = testdir.inline_runsource("""
import pytest
class pytestmark(object):
pass
def test_func():
pass
""")
values = reprec.getfailedcollections()
assert len(values) == 1
assert "TypeError" in str(values[0].longrepr)
def test_mark_dynamically_in_funcarg(self, testdir):
testdir.makeconftest("""
import pytest
@pytest.fixture
def arg(request):
request.applymarker(pytest.mark.hello)
def pytest_terminal_summary(terminalreporter):
values = terminalreporter.stats['passed']
terminalreporter._tw.line("keyword: %s" % values[0].keywords)
""")
testdir.makepyfile("""
def test_func(arg):
pass
""")
result = testdir.runpytest()
result.stdout.fnmatch_lines([
"keyword: *hello*"
])
@ignore_markinfo
def test_merging_markers_two_functions(self, testdir):
p = testdir.makepyfile("""
import pytest
@pytest.mark.hello("pos1", z=4)
@pytest.mark.hello("pos0", z=3)
def test_func():
pass
""")
items, rec = testdir.inline_genitems(p)
item, = items
keywords = item.keywords
marker = keywords['hello']
values = list(marker)
assert len(values) == 2
assert values[0].args == ("pos0",)
assert values[1].args == ("pos1",)
def test_no_marker_match_on_unmarked_names(self, testdir):
p = testdir.makepyfile("""
import pytest
@pytest.mark.shouldmatch
def test_marked():
assert 1
def test_unmarked():
assert 1
""")
reprec = testdir.inline_run("-m", "test_unmarked", p)
passed, skipped, failed = reprec.listoutcomes()
assert len(passed) + len(skipped) + len(failed) == 0
dlist = reprec.getcalls("pytest_deselected")
deselected_tests = dlist[0].items
assert len(deselected_tests) == 2
def test_keywords_at_node_level(self, testdir):
testdir.makepyfile("""
import pytest
@pytest.fixture(scope="session", autouse=True)
def some(request):
request.keywords["hello"] = 42
assert "world" not in request.keywords
@pytest.fixture(scope="function", autouse=True)
def funcsetup(request):
assert "world" in request.keywords
assert "hello" in request.keywords
@pytest.mark.world
def test_function():
pass
""")
reprec = testdir.inline_run()
reprec.assertoutcome(passed=1)
def test_keyword_added_for_session(self, testdir):
testdir.makeconftest("""
import pytest
def pytest_collection_modifyitems(session):
session.add_marker("mark1")
session.add_marker(pytest.mark.mark2)
session.add_marker(pytest.mark.mark3)
pytest.raises(ValueError, lambda:
session.add_marker(10))
""")
testdir.makepyfile("""
def test_some(request):
assert "mark1" in request.keywords
assert "mark2" in request.keywords
assert "mark3" in request.keywords
assert 10 not in request.keywords
marker = request.node.get_marker("mark1")
assert marker.name == "mark1"
assert marker.args == ()
assert marker.kwargs == {}
""")
reprec = testdir.inline_run("-m", "mark1")
reprec.assertoutcome(passed=1)
def assert_markers(self, items, **expected):
"""assert that given items have expected marker names applied to them.
expected should be a dict of (item name -> seq of expected marker names)
.. note:: this could be moved to ``testdir`` if proven to be useful
to other modules.
"""
from _pytest.mark import MarkInfo
items = dict((x.name, x) for x in items)
for name, expected_markers in expected.items():
markers = items[name].keywords._markers
marker_names = set([name for (name, v) in markers.items()
if isinstance(v, MarkInfo)])
assert marker_names == set(expected_markers)
2016-04-28 22:11:30 +08:00
@pytest.mark.issue1540
@pytest.mark.filterwarnings("ignore")
2016-04-28 22:11:30 +08:00
def test_mark_from_parameters(self, testdir):
testdir.makepyfile("""
import pytest
pytestmark = pytest.mark.skipif(True, reason='skip all')
# skipifs inside fixture params
params = [pytest.mark.skipif(False, reason='dont skip')('parameter')]
@pytest.fixture(params=params)
def parameter(request):
return request.param
def test_1(parameter):
assert True
""")
reprec = testdir.inline_run()
reprec.assertoutcome(skipped=1)
class TestKeywordSelection(object):
def test_select_simple(self, testdir):
file_test = testdir.makepyfile("""
def test_one():
assert 0
class TestClass(object):
def test_method_one(self):
assert 42 == 43
""")
def check(keyword, name):
reprec = testdir.inline_run("-s", "-k", keyword, file_test)
passed, skipped, failed = reprec.listoutcomes()
assert len(failed) == 1
assert failed[0].nodeid.split("::")[-1] == name
assert len(reprec.getcalls('pytest_deselected')) == 1
for keyword in ['test_one', 'est_on']:
check(keyword, 'test_one')
check('TestClass and test', 'test_method_one')
@pytest.mark.parametrize("keyword", [
'xxx', 'xxx and test_2', 'TestClass', 'xxx and not test_1',
'TestClass and test_2', 'xxx and TestClass and test_2'])
def test_select_extra_keywords(self, testdir, keyword):
p = testdir.makepyfile(test_select="""
def test_1():
pass
class TestClass(object):
def test_2(self):
pass
""")
testdir.makepyfile(conftest="""
import pytest
@pytest.hookimpl(hookwrapper=True)
def pytest_pycollect_makeitem(name):
outcome = yield
if name == "TestClass":
item = outcome.get_result()
item.extra_keyword_matches.add("xxx")
""")
reprec = testdir.inline_run(p.dirpath(), '-s', '-k', keyword)
print("keyword", repr(keyword))
passed, skipped, failed = reprec.listoutcomes()
assert len(passed) == 1
assert passed[0].nodeid.endswith("test_2")
dlist = reprec.getcalls("pytest_deselected")
assert len(dlist) == 1
assert dlist[0].items[0].name == 'test_1'
def test_select_starton(self, testdir):
threepass = testdir.makepyfile(test_threepass="""
def test_one(): assert 1
def test_two(): assert 1
def test_three(): assert 1
""")
reprec = testdir.inline_run("-k", "test_two:", threepass)
passed, skipped, failed = reprec.listoutcomes()
assert len(passed) == 2
assert not failed
dlist = reprec.getcalls("pytest_deselected")
assert len(dlist) == 1
item = dlist[0].items[0]
assert item.name == "test_one"
def test_keyword_extra(self, testdir):
p = testdir.makepyfile("""
def test_one():
assert 0
test_one.mykeyword = True
""")
reprec = testdir.inline_run("-k", "mykeyword", p)
passed, skipped, failed = reprec.countoutcomes()
assert failed == 1
@pytest.mark.xfail
def test_keyword_extra_dash(self, testdir):
p = testdir.makepyfile("""
def test_one():
assert 0
test_one.mykeyword = True
""")
# with argparse the argument to an option cannot
# start with '-'
reprec = testdir.inline_run("-k", "-mykeyword", p)
passed, skipped, failed = reprec.countoutcomes()
assert passed + skipped + failed == 0
def test_no_magic_values(self, testdir):
"""Make sure the tests do not match on magic values,
no double underscored values, like '__dict__',
and no instance values, like '()'.
"""
p = testdir.makepyfile("""
def test_one(): assert 1
""")
def assert_test_is_not_selected(keyword):
reprec = testdir.inline_run("-k", keyword, p)
passed, skipped, failed = reprec.countoutcomes()
dlist = reprec.getcalls("pytest_deselected")
assert passed + skipped + failed == 0
deselected_tests = dlist[0].items
assert len(deselected_tests) == 1
assert_test_is_not_selected("__")
assert_test_is_not_selected("()")
@pytest.mark.parametrize('argval, expected', [
(pytest.mark.skip()((1, 2)),
ParameterSet(values=(1, 2), marks=[pytest.mark.skip], id=None)),
(pytest.mark.xfail(pytest.mark.skip()((1, 2))),
ParameterSet(values=(1, 2),
marks=[pytest.mark.xfail, pytest.mark.skip], id=None)),
])
@pytest.mark.filterwarnings('ignore')
def test_parameterset_extractfrom(argval, expected):
extracted = ParameterSet.extract_from(argval)
assert extracted == expected
def test_legacy_transfer():
class FakeModule(object):
pytestmark = []
class FakeClass(object):
pytestmark = pytest.mark.nofun
@pytest.mark.fun
def fake_method(self):
pass
transfer_markers(fake_method, FakeClass, FakeModule)
# legacy marks transfer smeared
assert fake_method.nofun
assert fake_method.fun
# pristine marks dont transfer
2017-07-18 08:16:14 +08:00
assert fake_method.pytestmark == [pytest.mark.fun.mark]
class TestMarkDecorator(object):
@pytest.mark.parametrize('lhs, rhs, expected', [
(pytest.mark.foo(), pytest.mark.foo(), True),
(pytest.mark.foo(), pytest.mark.bar(), False),
(pytest.mark.foo(), 'bar', False),
('foo', pytest.mark.bar(), False)
])
def test__eq__(self, lhs, rhs, expected):
assert (lhs == rhs) == expected
@pytest.mark.parametrize('mark', [None, '', 'skip', 'xfail'])
def test_parameterset_for_parametrize_marks(testdir, mark):
if mark is not None:
testdir.makeini(
"[pytest]\n{}={}".format(EMPTY_PARAMETERSET_OPTION, mark))
config = testdir.parseconfig()
from _pytest.mark import pytest_configure, get_empty_parameterset_mark
pytest_configure(config)
result_mark = get_empty_parameterset_mark(config, ['a'], all)
if mark in (None, ''):
# normalize to the requested name
mark = 'skip'
assert result_mark.name == mark
assert result_mark.kwargs['reason'].startswith("got empty parameter set ")
if mark == 'xfail':
assert result_mark.kwargs.get('run') is False
def test_parameterset_for_parametrize_bad_markname(testdir):
with pytest.raises(pytest.UsageError):
test_parameterset_for_parametrize_marks(testdir, 'bad')