summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2021-02-02 10:53:27 -0500
committerGitHub <noreply@github.com>2021-02-02 10:53:27 -0500
commitb7160a896252bb92ffe921a37e3cde98c5cb78b9 (patch)
treea0edae6ca0996217b9f0fa3213f824eab8b1cbe1
parent35d91c7aa186a84d0edb333bad60b520f3b1d719 (diff)
parent80c021d9174e7ae3e5183f1902903fb90a891246 (diff)
downloadpython-coveragepy-git-b7160a896252bb92ffe921a37e3cde98c5cb78b9.tar.gz
Merge pull request #1113 from nedbat/nedbat/capsys
More unittest removal
-rw-r--r--coverage/backunittest.py10
-rw-r--r--tests/coveragetest.py34
-rw-r--r--tests/mixins.py70
-rw-r--r--tests/test_api.py12
-rw-r--r--tests/test_arcs.py5
-rw-r--r--tests/test_cmdline.py10
-rw-r--r--tests/test_execfile.py30
-rw-r--r--tests/test_testing.py3
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():