1255 lines
35 KiB
Python
1255 lines
35 KiB
Python
from __future__ import absolute_import
|
|
from __future__ import division
|
|
from __future__ import print_function
|
|
|
|
import os
|
|
import sys
|
|
|
|
from _pytest.warnings import SHOW_PYTEST_WARNINGS_ARG
|
|
|
|
try:
|
|
import mock
|
|
except ImportError:
|
|
import unittest.mock as mock
|
|
import pytest
|
|
from _pytest.mark import (
|
|
MarkGenerator as Mark,
|
|
ParameterSet,
|
|
transfer_markers,
|
|
EMPTY_PARAMETERSET_OPTION,
|
|
)
|
|
from _pytest.nodes import Node, Collector
|
|
|
|
ignore_markinfo = pytest.mark.filterwarnings(
|
|
"ignore:MarkInfo objects:pytest.RemovedInPytest4Warning"
|
|
)
|
|
|
|
|
|
class TestMark(object):
|
|
def test_markinfo_repr(self):
|
|
from _pytest.mark import MarkInfo, Mark
|
|
|
|
m = MarkInfo.for_mark(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)
|
|
|
|
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
|
|
|
|
def test_mark_legacy_ignore_fail(self):
|
|
def add_attribute(func):
|
|
func.foo = 1
|
|
return func
|
|
|
|
@pytest.mark.foo
|
|
@add_attribute
|
|
def test_fun():
|
|
pass
|
|
|
|
assert test_fun.foo == 1
|
|
assert test_fun.pytestmark
|
|
|
|
@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
|
|
def test_pytest_mark_positional_func_and_keyword(self):
|
|
mark = Mark()
|
|
|
|
def f():
|
|
raise Exception
|
|
|
|
m = mark.world(f, omega="hello")
|
|
|
|
def g():
|
|
pass
|
|
|
|
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
|
|
nodescription
|
|
"""
|
|
)
|
|
result = testdir.runpytest("--markers")
|
|
result.stdout.fnmatch_lines(
|
|
["*a1*this is a webtest*", "*a1some*another marker", "*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)
|
|
|
|
|
|
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("--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 a registered marker"])
|
|
|
|
|
|
@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.add_marker(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",
|
|
[
|
|
(
|
|
"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)
|
|
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'])"
|
|
]
|
|
)
|
|
|
|
|
|
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",)
|
|
|
|
def test_merging_markers_deep(self, testdir):
|
|
# issue 199 - propagate markers into nested classes
|
|
p = testdir.makepyfile(
|
|
"""
|
|
import pytest
|
|
class TestA(object):
|
|
pytestmark = pytest.mark.a
|
|
def test_b(self):
|
|
assert True
|
|
class TestC(object):
|
|
# 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 [x for x in item.iter_markers() if x.name == "a"]
|
|
|
|
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",))
|
|
|
|
@pytest.mark.issue568
|
|
def test_mark_should_not_pass_to_siebling_class(self, testdir):
|
|
p = testdir.makepyfile(
|
|
"""
|
|
import pytest
|
|
|
|
class TestBase(object):
|
|
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
|
|
print(items, [x.nodeid for x in items])
|
|
# legacy api smears
|
|
assert hasattr(base_item.obj, "b")
|
|
assert hasattr(sub_item_other.obj, "b")
|
|
assert hasattr(sub_item.obj, "b")
|
|
|
|
# new api seregates
|
|
assert not list(base_item.iter_markers(name="b"))
|
|
assert not list(sub_item_other.iter_markers(name="b"))
|
|
assert list(sub_item.iter_markers(name="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_closest(self, testdir):
|
|
p = testdir.makepyfile(
|
|
"""
|
|
import pytest
|
|
|
|
@pytest.mark.c(location="class")
|
|
class Test:
|
|
@pytest.mark.c(location="function")
|
|
def test_has_own():
|
|
pass
|
|
|
|
def test_has_inherited():
|
|
pass
|
|
|
|
"""
|
|
)
|
|
items, rec = testdir.inline_genitems(p)
|
|
has_own, has_inherited = items
|
|
assert has_own.get_closest_marker("c").kwargs == {"location": "function"}
|
|
assert has_inherited.get_closest_marker("c").kwargs == {"location": "class"}
|
|
assert has_own.get_closest_marker("missing") is None
|
|
|
|
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_invalid_m_option(self, testdir):
|
|
testdir.makepyfile(
|
|
"""
|
|
def test_a():
|
|
pass
|
|
"""
|
|
)
|
|
result = testdir.runpytest("-m bogus/")
|
|
result.stdout.fnmatch_lines(
|
|
["INTERNALERROR> Marker expression must be valid Python!"]
|
|
)
|
|
|
|
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)
|
|
|
|
@ignore_markinfo
|
|
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", SHOW_PYTEST_WARNINGS_ARG)
|
|
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 = {x.name: x for x in items}
|
|
for name, expected_markers in expected.items():
|
|
markers = items[name].keywords._markers
|
|
marker_names = {
|
|
name for (name, v) in markers.items() if isinstance(v, MarkInfo)
|
|
}
|
|
assert marker_names == set(expected_markers)
|
|
|
|
@pytest.mark.issue1540
|
|
@pytest.mark.filterwarnings("ignore")
|
|
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(SHOW_PYTEST_WARNINGS_ARG)
|
|
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("default")
|
|
def test_parameterset_extractfrom(argval, expected):
|
|
from _pytest.deprecated import MARK_PARAMETERSET_UNPACKING
|
|
|
|
warn_called = []
|
|
|
|
class DummyItem:
|
|
def warn(self, warning):
|
|
warn_called.append(warning)
|
|
|
|
extracted = ParameterSet.extract_from(argval, belonging_definition=DummyItem())
|
|
assert extracted == expected
|
|
assert warn_called == [MARK_PARAMETERSET_UNPACKING]
|
|
|
|
|
|
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
|
|
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]
|
|
{}={}
|
|
""".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_fail_at_collect(testdir):
|
|
testdir.makeini(
|
|
"""
|
|
[pytest]
|
|
{}=fail_at_collect
|
|
""".format(
|
|
EMPTY_PARAMETERSET_OPTION
|
|
)
|
|
)
|
|
|
|
config = testdir.parseconfig()
|
|
from _pytest.mark import pytest_configure, get_empty_parameterset_mark
|
|
from _pytest.compat import getfslineno
|
|
|
|
pytest_configure(config)
|
|
|
|
test_func = all
|
|
func_name = test_func.__name__
|
|
_, func_lineno = getfslineno(test_func)
|
|
expected_errmsg = r"Empty parameter set in '%s' at line %d" % (
|
|
func_name,
|
|
func_lineno,
|
|
)
|
|
|
|
with pytest.raises(Collector.CollectError, match=expected_errmsg):
|
|
get_empty_parameterset_mark(config, ["a"], test_func)
|
|
|
|
|
|
def test_parameterset_for_parametrize_bad_markname(testdir):
|
|
with pytest.raises(pytest.UsageError):
|
|
test_parameterset_for_parametrize_marks(testdir, "bad")
|
|
|
|
|
|
def test_mark_expressions_no_smear(testdir):
|
|
testdir.makepyfile(
|
|
"""
|
|
import pytest
|
|
|
|
class BaseTests(object):
|
|
def test_something(self):
|
|
pass
|
|
|
|
@pytest.mark.FOO
|
|
class TestFooClass(BaseTests):
|
|
pass
|
|
|
|
@pytest.mark.BAR
|
|
class TestBarClass(BaseTests):
|
|
pass
|
|
"""
|
|
)
|
|
|
|
reprec = testdir.inline_run("-m", "FOO")
|
|
passed, skipped, failed = reprec.countoutcomes()
|
|
dlist = reprec.getcalls("pytest_deselected")
|
|
assert passed == 1
|
|
assert skipped == failed == 0
|
|
deselected_tests = dlist[0].items
|
|
assert len(deselected_tests) == 1
|
|
|
|
# keywords smear - expected behaviour
|
|
reprec_keywords = testdir.inline_run("-k", "FOO")
|
|
passed_k, skipped_k, failed_k = reprec_keywords.countoutcomes()
|
|
assert passed_k == 2
|
|
assert skipped_k == failed_k == 0
|
|
|
|
|
|
def test_addmarker_getmarker():
|
|
node = Node("Test", config=mock.Mock(), session=mock.Mock(), nodeid="Test")
|
|
node.add_marker(pytest.mark.a(1))
|
|
node.add_marker("b")
|
|
node.get_marker("a").combined
|
|
node.get_marker("b").combined
|
|
|
|
|
|
def test_addmarker_order():
|
|
node = Node("Test", config=mock.Mock(), session=mock.Mock(), nodeid="Test")
|
|
node.add_marker("a")
|
|
node.add_marker("b")
|
|
node.add_marker("c", append=False)
|
|
extracted = [x.name for x in node.iter_markers()]
|
|
assert extracted == ["c", "a", "b"]
|
|
|
|
|
|
@pytest.mark.issue("https://github.com/pytest-dev/pytest/issues/3605")
|
|
@pytest.mark.filterwarnings("ignore")
|
|
def test_markers_from_parametrize(testdir):
|
|
testdir.makepyfile(
|
|
"""
|
|
from __future__ import print_function
|
|
import pytest
|
|
|
|
first_custom_mark = pytest.mark.custom_marker
|
|
custom_mark = pytest.mark.custom_mark
|
|
@pytest.fixture(autouse=True)
|
|
def trigger(request):
|
|
custom_mark =request.node.get_marker('custom_mark')
|
|
print("Custom mark %s" % custom_mark)
|
|
|
|
@custom_mark("custom mark non parametrized")
|
|
def test_custom_mark_non_parametrized():
|
|
print("Hey from test")
|
|
|
|
@pytest.mark.parametrize(
|
|
"obj_type",
|
|
[
|
|
first_custom_mark("first custom mark")("template"),
|
|
pytest.param( # Think this should be recommended way?
|
|
"disk",
|
|
marks=custom_mark('custom mark1')
|
|
),
|
|
custom_mark("custom mark2")("vm"), # Tried also this
|
|
]
|
|
)
|
|
def test_custom_mark_parametrized(obj_type):
|
|
print("obj_type is:", obj_type)
|
|
"""
|
|
)
|
|
|
|
result = testdir.runpytest(SHOW_PYTEST_WARNINGS_ARG)
|
|
result.assert_outcomes(passed=4)
|