From 04a98700d9693ffb2bd9c15a4c76fe5850f90134 Mon Sep 17 00:00:00 2001 From: holger krekel Date: Fri, 17 Jul 2009 18:07:37 +0200 Subject: [PATCH] * move some test_pytest_terminal tests to become functional/acceptance tests * refine pytest_namespace to not take a config object --HG-- branch : 1.0.x --- doc/test/extend.txt | 4 +- py/test/plugin/hookspec.py | 6 +- py/test/plugin/pytest__pytest.py | 2 +- py/test/plugin/pytest_keyword.py | 2 +- py/test/plugin/pytest_recwarn.py | 2 +- py/test/plugin/test_pytest_terminal.py | 174 +++++++++---------------- py/test/pluginmanager.py | 4 +- py/test/testing/test_pluginmanager.py | 2 +- 8 files changed, 74 insertions(+), 122 deletions(-) diff --git a/doc/test/extend.txt b/doc/test/extend.txt index 641cae87d..8837f5129 100644 --- a/doc/test/extend.txt +++ b/doc/test/extend.txt @@ -135,8 +135,8 @@ adding global py.test helpers and functionality If you want to make global helper functions or objects available to your test code you can implement: - def pytest_namespace(config): - """ return dictionary with items to be made available on py.test. """ + def pytest_namespace(): + """ return dictionary with items to be made available on py.test. namespace """ All such returned items will be made available directly on the ``py.test`` namespace. diff --git a/py/test/plugin/hookspec.py b/py/test/plugin/hookspec.py index a20f87556..0199ba723 100644 --- a/py/test/plugin/hookspec.py +++ b/py/test/plugin/hookspec.py @@ -9,15 +9,15 @@ py.test plugin hooks def pytest_addoption(parser): """ called before commandline parsing. """ +def pytest_namespace(): + """ return dict of name->object which will get stored at py.test. namespace""" + def pytest_configure(config): """ called after command line options have been parsed. and all plugins and initial conftest files been loaded. ``config`` provides access to all such configuration values. """ -def pytest_namespace(config): - """ return dict of name->object to become available at py.test.*""" - def pytest_unconfigure(config): """ called before test process is exited. """ diff --git a/py/test/plugin/pytest__pytest.py b/py/test/plugin/pytest__pytest.py index c207a011d..489b4ab66 100644 --- a/py/test/plugin/pytest__pytest.py +++ b/py/test/plugin/pytest__pytest.py @@ -57,7 +57,7 @@ class HookRecorder: def _makecallparser(self, method): name = method.__name__ args, varargs, varkw, default = py.std.inspect.getargspec(method) - if args[0] != "self": + if args and args[0] != "self": args.insert(0, 'self') fspec = py.std.inspect.formatargspec(args, varargs, varkw, default) # we use exec because we want to have early type diff --git a/py/test/plugin/pytest_keyword.py b/py/test/plugin/pytest_keyword.py index 4b326bcc6..61c134a01 100644 --- a/py/test/plugin/pytest_keyword.py +++ b/py/test/plugin/pytest_keyword.py @@ -3,7 +3,7 @@ """ import py -def pytest_namespace(config): +def pytest_namespace(): mark = KeywordDecorator({}) return {'mark': mark} diff --git a/py/test/plugin/pytest_recwarn.py b/py/test/plugin/pytest_recwarn.py index 524231135..4625d49dd 100644 --- a/py/test/plugin/pytest_recwarn.py +++ b/py/test/plugin/pytest_recwarn.py @@ -16,7 +16,7 @@ def pytest_funcarg__recwarn(request): request.addfinalizer(warnings.finalize) return warnings -def pytest_namespace(config): +def pytest_namespace(): return {'deprecated_call': deprecated_call} def deprecated_call(func, *args, **kwargs): diff --git a/py/test/plugin/test_pytest_terminal.py b/py/test/plugin/test_pytest_terminal.py index a299c5a97..f52f07b4e 100644 --- a/py/test/plugin/test_pytest_terminal.py +++ b/py/test/plugin/test_pytest_terminal.py @@ -16,9 +16,31 @@ from pytest_terminal import repr_pythonversion, folded_skips def basic_run_report(item): return runner.call_and_report(item, "call", log=False) +class Option: + def __init__(self, verbose=False): + self.verbose = verbose + def _getcmdargs(self): + l = [] + if self.verbose: + l.append('-v') + return l + def _getcmdstring(self): + return " ".join(self._getcmdargs()) + +def pytest_generate_tests(metafunc): + if "option" in metafunc.funcargnames: + metafunc.addcall( + id="default", + funcargs={'option': Option(verbose=False)} + ) + metafunc.addcall( + id="verbose", + funcargs={'option': Option(verbose=True)} + ) + class TestTerminal: - def test_pass_skip_fail(self, testdir, linecomp): - modcol = testdir.getmodulecol(""" + def test_pass_skip_fail(self, testdir, option): + p = testdir.makepyfile(""" import py def test_ok(): pass @@ -27,70 +49,30 @@ class TestTerminal: def test_func(): assert 0 """) - rep = TerminalReporter(modcol.config, file=linecomp.stringio) - rep.config.pluginmanager.register(rep) - rep.config.hook.pytest_sessionstart(session=testdir.session) - - for item in testdir.genitems([modcol]): - ev = basic_run_report(item) - rep.config.hook.pytest_runtest_logreport(rep=ev) - linecomp.assert_contains_lines([ - "*test_pass_skip_fail.py .sF" + result = testdir.runpytest(option._getcmdstring()) + if option.verbose: + result.stdout.fnmatch_lines([ + "*test_pass_skip_fail.py:2: *test_ok*PASS*", + "*test_pass_skip_fail.py:4: *test_skip*SKIP*", + "*test_pass_skip_fail.py:6: *test_func*FAIL*", + ]) + else: + result.stdout.fnmatch_lines([ + "*test_pass_skip_fail.py .sF" ]) - rep.config.hook.pytest_sessionfinish(session=testdir.session, exitstatus=1) - linecomp.assert_contains_lines([ + result.stdout.fnmatch_lines([ " def test_func():", "> assert 0", "E assert 0", ]) - def test_pass_skip_fail_verbose(self, testdir, linecomp): - modcol = testdir.getmodulecol(""" - import py - def test_ok(): - pass - def test_skip(): - py.test.skip("xx") - def test_func(): - assert 0 - """, configargs=("-v",)) - rep = TerminalReporter(modcol.config, file=linecomp.stringio) - rep.config.pluginmanager.register(rep) - rep.config.hook.pytest_sessionstart(session=testdir.session) - items = modcol.collect() - rep.config.option.debug = True # - for item in items: - rep.config.hook.pytest_itemstart(item=item, node=None) - s = linecomp.stringio.getvalue().strip() - assert s.endswith(item.name) - rep.config.hook.pytest_runtest_logreport(rep=basic_run_report(item)) - - linecomp.assert_contains_lines([ - "*test_pass_skip_fail_verbose.py:2: *test_ok*PASS*", - "*test_pass_skip_fail_verbose.py:4: *test_skip*SKIP*", - "*test_pass_skip_fail_verbose.py:6: *test_func*FAIL*", - ]) - rep.config.hook.pytest_sessionfinish(session=testdir.session, exitstatus=1) - linecomp.assert_contains_lines([ - " def test_func():", - "> assert 0", - "E assert 0", - ]) - - def test_collect_fail(self, testdir, linecomp): - modcol = testdir.getmodulecol("import xyz") - rep = TerminalReporter(modcol.config, file=linecomp.stringio) - rep.config.pluginmanager.register(rep) - rep.config.hook.pytest_sessionstart(session=testdir.session) - l = list(testdir.genitems([modcol])) - assert len(l) == 0 - linecomp.assert_contains_lines([ - "*test_collect_fail.py F*" - ]) - rep.config.hook.pytest_sessionfinish(session=testdir.session, exitstatus=1) - linecomp.assert_contains_lines([ + def test_collect_fail(self, testdir, option): + p = testdir.makepyfile("import xyz") + result = testdir.runpytest(option._getcmdstring()) + result.stdout.fnmatch_lines([ + "*test_collect_fail.py F*", "> import xyz", - "E ImportError: No module named xyz" + "E ImportError: No module named xyz", ]) def test_internalerror(self, testdir, linecomp): @@ -163,28 +145,20 @@ class TestTerminal: "*%s*" % (modcol.config.topdir), ]) - def test_tb_option(self, testdir, linecomp): - # XXX usage of testdir + def test_tb_option(self, testdir, option): + p = testdir.makepyfile(""" + import py + def g(): + raise IndexError + def test_func(): + print 6*7 + g() # --calling-- + """) for tbopt in ["long", "short", "no"]: print 'testing --tb=%s...' % tbopt - modcol = testdir.getmodulecol(""" - import py - def g(): - raise IndexError - def test_func(): - print 6*7 - g() # --calling-- - """, configargs=("--tb=%s" % tbopt,)) - rep = TerminalReporter(modcol.config, file=linecomp.stringio) - rep.config.pluginmanager.register(rep) - rep.config.hook.pytest_sessionstart(session=testdir.session) - for item in testdir.genitems([modcol]): - rep.config.hook.pytest_runtest_logreport( - rep=basic_run_report(item)) - rep.config.hook.pytest_sessionfinish(session=testdir.session, exitstatus=1) - s = linecomp.stringio.getvalue() + result = testdir.runpytest('--tb=%s' % tbopt) + s = result.stdout.str() if tbopt == "long": - print s assert 'print 6*7' in s else: assert 'print 6*7' not in s @@ -195,7 +169,6 @@ class TestTerminal: assert 'FAILURES' not in s assert '--calling--' not in s assert 'IndexError' not in s - linecomp.stringio.truncate(0) def test_show_path_before_running_test(self, testdir, linecomp): item = testdir.getitem("def test_func(): pass") @@ -245,48 +218,27 @@ class TestTerminal: ]) - def pseudo_keyboard_interrupt(self, testdir, linecomp, verbose=False): - modcol = testdir.getmodulecol(""" + def test_keyboard_interrupt(self, testdir, option): + p = testdir.makepyfile(""" def test_foobar(): assert 0 def test_spamegg(): import py; py.test.skip('skip me please!') def test_interrupt_me(): raise KeyboardInterrupt # simulating the user - """, configargs=("-v",)*verbose) - #""", configargs=("--showskipsummary",) + ("-v",)*verbose) - rep = TerminalReporter(modcol.config, file=linecomp.stringio) - modcol.config.pluginmanager.register(rep) - modcol.config.hook.pytest_sessionstart(session=testdir.session) - try: - for item in testdir.genitems([modcol]): - modcol.config.hook.pytest_runtest_logreport( - rep=basic_run_report(item)) - except KeyboardInterrupt: - excinfo = py.code.ExceptionInfo() - else: - py.test.fail("no KeyboardInterrupt??") - s = linecomp.stringio.getvalue() - if not verbose: - assert s.find("_keyboard_interrupt.py Fs") != -1 - modcol.config.hook.pytest_sessionfinish( - session=testdir.session, exitstatus=2, excrepr=excinfo.getrepr()) - text = linecomp.stringio.getvalue() - linecomp.assert_contains_lines([ + """) + + result = testdir.runpytest(option._getcmdstring()) + result.stdout.fnmatch_lines([ " def test_foobar():", "> assert 0", "E assert 0", + "*_keyboard_interrupt.py:6: KeyboardInterrupt*", ]) - #assert "Skipped: 'skip me please!'" in text - assert "_keyboard_interrupt.py:6: KeyboardInterrupt" in text - see_details = "raise KeyboardInterrupt # simulating the user" in text - assert see_details == verbose - - def test_keyboard_interrupt(self, testdir, linecomp): - self.pseudo_keyboard_interrupt(testdir, linecomp) - - def test_verbose_keyboard_interrupt(self, testdir, linecomp): - self.pseudo_keyboard_interrupt(testdir, linecomp, verbose=True) + if option.verbose: + result.stdout.fnmatch_lines([ + "*raise KeyboardInterrupt # simulating the user*", + ]) def test_skip_reasons_folding(self): class longrepr: diff --git a/py/test/pluginmanager.py b/py/test/pluginmanager.py index 4ab5a4a66..d9c6860a2 100644 --- a/py/test/pluginmanager.py +++ b/py/test/pluginmanager.py @@ -174,7 +174,7 @@ class PluginManager(object): if hasattr(self, '_config'): self.call_plugin(plugin, "pytest_addoption", parser=self._config._parser) self.call_plugin(plugin, "pytest_configure", config=self._config) - #dic = self.call_plugin(plugin, "pytest_namespace", config=self._config) + #dic = self.call_plugin(plugin, "pytest_namespace") #self._updateext(dic) def call_plugin(self, plugin, methname, **kwargs): @@ -191,7 +191,7 @@ class PluginManager(object): config.pluginmanager.register(self) self._config = config config.hook.pytest_configure(config=self._config) - for dic in config.hook.pytest_namespace(config=config) or []: + for dic in config.hook.pytest_namespace() or []: self._updateext(dic) def do_unconfigure(self, config): diff --git a/py/test/testing/test_pluginmanager.py b/py/test/testing/test_pluginmanager.py index 38ba3959a..a4ea7f27d 100644 --- a/py/test/testing/test_pluginmanager.py +++ b/py/test/testing/test_pluginmanager.py @@ -175,7 +175,7 @@ class TestPytestPluginInteractions: def test_do_ext_namespace(self, testdir): testdir.makeconftest(""" - def pytest_namespace(config): + def pytest_namespace(): return {'hello': 'world'} """) p = testdir.makepyfile("""