diff options
author | Ned Batchelder <ned@nedbatchelder.com> | 2021-02-02 10:53:27 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-02-02 10:53:27 -0500 |
commit | b7160a896252bb92ffe921a37e3cde98c5cb78b9 (patch) | |
tree | a0edae6ca0996217b9f0fa3213f824eab8b1cbe1 | |
parent | 35d91c7aa186a84d0edb333bad60b520f3b1d719 (diff) | |
parent | 80c021d9174e7ae3e5183f1902903fb90a891246 (diff) | |
download | python-coveragepy-git-b7160a896252bb92ffe921a37e3cde98c5cb78b9.tar.gz |
Merge pull request #1113 from nedbat/nedbat/capsys
More unittest removal
-rw-r--r-- | coverage/backunittest.py | 10 | ||||
-rw-r--r-- | tests/coveragetest.py | 34 | ||||
-rw-r--r-- | tests/mixins.py | 70 | ||||
-rw-r--r-- | tests/test_api.py | 12 | ||||
-rw-r--r-- | tests/test_arcs.py | 5 | ||||
-rw-r--r-- | tests/test_cmdline.py | 10 | ||||
-rw-r--r-- | tests/test_execfile.py | 30 | ||||
-rw-r--r-- | tests/test_testing.py | 3 |
8 files changed, 108 insertions, 66 deletions
diff --git a/coverage/backunittest.py b/coverage/backunittest.py index 123bb2a1..8b66c0f1 100644 --- a/coverage/backunittest.py +++ b/coverage/backunittest.py @@ -18,16 +18,8 @@ class TestCase(unittest.TestCase): `unittest` doesn't have them. """ - # pylint: disable=signature-differs, deprecated-method + # pylint: disable=signature-differs if not unittest_has('assertCountEqual'): def assertCountEqual(self, *args, **kwargs): return self.assertItemsEqual(*args, **kwargs) - - if not unittest_has('assertRaisesRegex'): - def assertRaisesRegex(self, *args, **kwargs): - return self.assertRaisesRegexp(*args, **kwargs) - - if not unittest_has('assertRegex'): - def assertRegex(self, *args, **kwargs): - return self.assertRegexpMatches(*args, **kwargs) diff --git a/tests/coveragetest.py b/tests/coveragetest.py index c4a46da9..71f4e2c8 100644 --- a/tests/coveragetest.py +++ b/tests/coveragetest.py @@ -6,7 +6,6 @@ import contextlib import datetime import difflib -import functools import glob import os import os.path @@ -14,20 +13,19 @@ import random import re import shlex import sys -import types import pytest -from unittest_mixins import EnvironmentAwareMixin, StdStreamCapturingMixin, TempDirMixin +from unittest_mixins import EnvironmentAwareMixin, TempDirMixin import coverage from coverage import env -from coverage.backunittest import TestCase, unittest +from coverage.backunittest import TestCase from coverage.backward import StringIO, import_local_file, string_class, shlex_quote from coverage.cmdline import CoverageScript -from coverage.misc import StopEverything from tests.helpers import arcs_to_arcz_repr, arcz_to_arcs from tests.helpers import run_command, SuperModuleCleaner +from tests.mixins import StdStreamCapturingMixin, StopEverythingMixin # Status returns for the command line. @@ -37,35 +35,11 @@ OK, ERR = 0, 1 TESTS_DIR = os.path.dirname(__file__) -def convert_skip_exceptions(method): - """A decorator for test methods to convert StopEverything to SkipTest.""" - @functools.wraps(method) - def _wrapper(*args, **kwargs): - try: - result = method(*args, **kwargs) - except StopEverything: - raise unittest.SkipTest("StopEverything!") - return result - return _wrapper - - -class SkipConvertingMetaclass(type): - """Decorate all test methods to convert StopEverything to SkipTest.""" - def __new__(cls, name, bases, attrs): - for attr_name, attr_value in attrs.items(): - if attr_name.startswith('test_') and isinstance(attr_value, types.FunctionType): - attrs[attr_name] = convert_skip_exceptions(attr_value) - - return super(SkipConvertingMetaclass, cls).__new__(cls, name, bases, attrs) - - -CoverageTestMethodsMixin = SkipConvertingMetaclass('CoverageTestMethodsMixin', (), {}) - class CoverageTest( EnvironmentAwareMixin, StdStreamCapturingMixin, TempDirMixin, - CoverageTestMethodsMixin, + StopEverythingMixin, TestCase, ): """A base class for coverage.py test cases.""" diff --git a/tests/mixins.py b/tests/mixins.py new file mode 100644 index 00000000..ab0623c0 --- /dev/null +++ b/tests/mixins.py @@ -0,0 +1,70 @@ +# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +# For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt + +""" +Test class mixins + +Some of these are transitional while working toward pure-pytest style. +""" + +import functools +import types + +import pytest + +from coverage.backunittest import unittest +from coverage.misc import StopEverything + + +def convert_skip_exceptions(method): + """A decorator for test methods to convert StopEverything to SkipTest.""" + @functools.wraps(method) + def _wrapper(*args, **kwargs): + try: + result = method(*args, **kwargs) + except StopEverything: + raise unittest.SkipTest("StopEverything!") + return result + return _wrapper + + +class SkipConvertingMetaclass(type): + """Decorate all test methods to convert StopEverything to SkipTest.""" + def __new__(cls, name, bases, attrs): + for attr_name, attr_value in attrs.items(): + if attr_name.startswith('test_') and isinstance(attr_value, types.FunctionType): + attrs[attr_name] = convert_skip_exceptions(attr_value) + + return super(SkipConvertingMetaclass, cls).__new__(cls, name, bases, attrs) + + +StopEverythingMixin = SkipConvertingMetaclass('StopEverythingMixin', (), {}) + + +class StdStreamCapturingMixin: + """ + Adapter from the pytest capsys fixture to more convenient methods. + + This doesn't also output to the real stdout, so we probably want to move + to "real" capsys when we can use fixtures in test methods. + + Once you've used one of these methods, the capturing is reset, so another + invocation will only return the delta. + + """ + @pytest.fixture(autouse=True) + def _capcapsys(self, capsys): + """Grab the fixture so our methods can use it.""" + self.capsys = capsys + + def stdouterr(self): + """Returns (out, err), two strings for stdout and stderr.""" + return self.capsys.readouterr() + + def stdout(self): + """Returns a string, the captured stdout.""" + return self.capsys.readouterr().out + + def stderr(self): + """Returns a string, the captured stderr.""" + return self.capsys.readouterr().err diff --git a/tests/test_api.py b/tests/test_api.py index bce431f3..ea625ff1 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -22,7 +22,7 @@ from coverage.data import line_counts from coverage.files import abs_file, relative_filename from coverage.misc import CoverageException -from tests.coveragetest import CoverageTest, CoverageTestMethodsMixin, TESTS_DIR, UsingModulesMixin +from tests.coveragetest import CoverageTest, StopEverythingMixin, TESTS_DIR, UsingModulesMixin class ApiTest(CoverageTest): @@ -520,10 +520,8 @@ class ApiTest(CoverageTest): self.start_import_stop(cov, "hello") cov.get_data() - out = self.stdout() + out, err = self.stdouterr() assert "Hello\n" in out - - err = self.stderr() assert textwrap.dedent("""\ Coverage.py warning: Module sys has no Python source. (module-not-python) Coverage.py warning: Module xyzzy was never imported. (module-not-imported) @@ -544,10 +542,8 @@ class ApiTest(CoverageTest): self.start_import_stop(cov, "hello") cov.get_data() - out = self.stdout() + out, err = self.stdouterr() assert "Hello\n" in out - - err = self.stderr() assert "Coverage.py warning: Module sys has no Python source. (module-not-python)" in err assert "module-not-imported" not in err assert "no-data-collected" not in err @@ -794,7 +790,7 @@ class NamespaceModuleTest(UsingModulesMixin, CoverageTest): cov.report() -class IncludeOmitTestsMixin(UsingModulesMixin, CoverageTestMethodsMixin): +class IncludeOmitTestsMixin(UsingModulesMixin, StopEverythingMixin): """Test methods for coverage methods taking include and omit.""" # We don't write any source files, but the data file will collide with diff --git a/tests/test_arcs.py b/tests/test_arcs.py index 3b63bcc2..66777751 100644 --- a/tests/test_arcs.py +++ b/tests/test_arcs.py @@ -1370,7 +1370,8 @@ class MiscArcTest(CoverageTest): # opcodes. # Note that we no longer interpret bytecode at all, but it couldn't # hurt to keep the test... - for n in [10, 50, 100, 500, 1000, 2000]: + sizes = [10, 50, 100, 500, 1000, 2000] + for n in sizes: code = """\ data = [ """ + "".join("""\ @@ -1383,7 +1384,7 @@ class MiscArcTest(CoverageTest): print(len(data)) """ self.check_coverage(code, arcs=[(-1, 1), (1, 2*n+4), (2*n+4, -1)]) - assert self.stdout().split()[-1] == str(n) + assert self.stdout().split() == [str(n) for n in sizes] def test_partial_generators(self): # https://github.com/nedbat/coveragepy/issues/475 diff --git a/tests/test_cmdline.py b/tests/test_cmdline.py index a0744452..0eb26cd0 100644 --- a/tests/test_cmdline.py +++ b/tests/test_cmdline.py @@ -545,8 +545,9 @@ class CmdLineTest(BaseCmdLineTest): # config file. self.command_line("run --concurrency=multiprocessing --branch foo.py", ret=ERR) msg = "Options affecting multiprocessing must only be specified in a configuration file." - assert msg in self.stderr() - assert "Remove --branch from the command line." in self.stderr() + _, err = self.stdouterr() + assert msg in err + assert "Remove --branch from the command line." in err def test_run_debug(self): self.cmd_executes("run --debug=opt1 foo.py", """\ @@ -915,8 +916,9 @@ class CmdMainTest(CoverageTest): def test_raise(self): ret = coverage.cmdline.main(['raise']) assert ret == 1 - assert self.stdout() == "" - err = self.stderr().split('\n') + out, err = self.stdouterr() + assert out == "" + err = err.split('\n') assert err[0] == 'Traceback (most recent call last):' assert err[-3] == ' raise Exception("oh noes!")' assert err[-2] == 'Exception: oh noes!' diff --git a/tests/test_execfile.py b/tests/test_execfile.py index db78d0f6..d221f2d3 100644 --- a/tests/test_execfile.py +++ b/tests/test_execfile.py @@ -193,33 +193,39 @@ class RunModuleTest(UsingModulesMixin, CoverageTest): def test_runmod1(self): run_python_module(["runmod1", "hello"]) - assert self.stderr() == "" - assert self.stdout() == "runmod1: passed hello\n" + out, err = self.stdouterr() + assert out == "runmod1: passed hello\n" + assert err == "" def test_runmod2(self): run_python_module(["pkg1.runmod2", "hello"]) - assert self.stderr() == "" - assert self.stdout() == "pkg1.__init__: pkg1\nrunmod2: passed hello\n" + out, err = self.stdouterr() + assert out == "pkg1.__init__: pkg1\nrunmod2: passed hello\n" + assert err == "" def test_runmod3(self): run_python_module(["pkg1.sub.runmod3", "hello"]) - assert self.stderr() == "" - assert self.stdout() == "pkg1.__init__: pkg1\nrunmod3: passed hello\n" + out, err = self.stdouterr() + assert out == "pkg1.__init__: pkg1\nrunmod3: passed hello\n" + assert err == "" def test_pkg1_main(self): run_python_module(["pkg1", "hello"]) - assert self.stderr() == "" - assert self.stdout() == "pkg1.__init__: pkg1\npkg1.__main__: passed hello\n" + out, err = self.stdouterr() + assert out == "pkg1.__init__: pkg1\npkg1.__main__: passed hello\n" + assert err == "" def test_pkg1_sub_main(self): run_python_module(["pkg1.sub", "hello"]) - assert self.stderr() == "" - assert self.stdout() == "pkg1.__init__: pkg1\npkg1.sub.__main__: passed hello\n" + out, err = self.stdouterr() + assert out == "pkg1.__init__: pkg1\npkg1.sub.__main__: passed hello\n" + assert err == "" def test_pkg1_init(self): run_python_module(["pkg1.__init__", "wut?"]) - assert self.stderr() == "" - assert self.stdout() == "pkg1.__init__: pkg1\npkg1.__init__: __main__\n" + out, err = self.stdouterr() + assert out == "pkg1.__init__: pkg1\npkg1.__init__: __main__\n" + assert err == "" def test_no_such_module(self): with pytest.raises(NoSource, match="No module named '?i_dont_exist'?"): diff --git a/tests/test_testing.py b/tests/test_testing.py index 21e09dcc..b6ffe1a0 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -17,11 +17,12 @@ from coverage.backunittest import TestCase, unittest from coverage.files import actual_path from coverage.misc import StopEverything -from tests.coveragetest import CoverageTest, convert_skip_exceptions +from tests.coveragetest import CoverageTest from tests.helpers import ( arcs_to_arcz_repr, arcz_to_arcs, CheckUniqueFilenames, re_lines, re_line, without_module, ) +from tests.mixins import convert_skip_exceptions def test_xdist_sys_path_nuttiness_is_fixed(): |