Add capsysbinary fixture

`capsysbinary` works like `capsys` but produces bytes for `readouterr()`.
This commit is contained in:
Anthony Sottile 2017-11-17 09:02:46 -08:00
parent 6161bcff6e
commit 219b758949
4 changed files with 76 additions and 10 deletions

View File

@ -180,7 +180,7 @@ class CaptureManager:
item.add_report_section(when, "stderr", err) item.add_report_section(when, "stderr", err)
capture_fixtures = {'capfd', 'capfdbinary', 'capsys'} capture_fixtures = {'capfd', 'capfdbinary', 'capsys', 'capsysbinary'}
def _ensure_only_one_capture_fixture(request, name): def _ensure_only_one_capture_fixture(request, name):
@ -207,6 +207,22 @@ def capsys(request):
yield fixture yield fixture
@pytest.fixture
def capsysbinary(request):
"""Enable capturing of writes to sys.stdout/sys.stderr and make
captured output available via ``capsys.readouterr()`` method calls
which return a ``(out, err)`` tuple. ``out`` and ``err`` will be ``bytes``
objects.
"""
_ensure_only_one_capture_fixture(request, 'capsysbinary')
# Currently, the implementation uses the python3 specific `.buffer`
# property of CaptureIO.
if sys.version_info < (3,):
raise request.raiseerror('capsysbinary is only supported on python 3')
with _install_capture_fixture_on_item(request, SysCaptureBinary) as fixture:
yield fixture
@pytest.fixture @pytest.fixture
def capfd(request): def capfd(request):
"""Enable capturing of writes to file descriptors 1 and 2 and make """Enable capturing of writes to file descriptors 1 and 2 and make
@ -506,10 +522,9 @@ class SysCapture:
setattr(sys, self.name, self.tmpfile) setattr(sys, self.name, self.tmpfile)
def snap(self): def snap(self):
f = self.tmpfile res = self.tmpfile.getvalue()
res = f.getvalue() self.tmpfile.seek(0)
f.truncate(0) self.tmpfile.truncate()
f.seek(0)
return res return res
def done(self): def done(self):
@ -528,6 +543,14 @@ class SysCapture:
self._old.flush() self._old.flush()
class SysCaptureBinary(SysCapture):
def snap(self):
res = self.tmpfile.buffer.getvalue()
self.tmpfile.seek(0)
self.tmpfile.truncate()
return res
class DontReadFromInput: class DontReadFromInput:
"""Temporary stub class. Ideally when stdin is accessed, the """Temporary stub class. Ideally when stdin is accessed, the
capturing should be turned off, with possibly all data captured capturing should be turned off, with possibly all data captured

2
changelog/2934.feature Normal file
View File

@ -0,0 +1,2 @@
Add ``capsysbinary`` a version of ``capsys`` which returns bytes from
``readouterr()``.

View File

@ -85,9 +85,9 @@ of the failing function and hide the other one::
Accessing captured output from a test function Accessing captured output from a test function
--------------------------------------------------- ---------------------------------------------------
The ``capsys``, ``capfd``, and ``capfdbinary`` fixtures allow access to The ``capsys``, ``capsysbinary``, ``capfd``, and ``capfdbinary`` fixtures
stdout/stderr output created during test execution. Here is an example test allow access to stdout/stderr output created during test execution. Here is
function that performs some output related checks: an example test function that performs some output related checks:
.. code-block:: python .. code-block:: python
@ -115,11 +115,20 @@ same interface but allows to also capture output from
libraries or subprocesses that directly write to operating libraries or subprocesses that directly write to operating
system level output streams (FD1 and FD2). system level output streams (FD1 and FD2).
.. versionadded:: 3.3
If the code under test writes non-textual data, you can capture this using
the ``capsysbinary`` fixture which instead returns ``bytes`` from
the ``readouterr`` method. The ``capfsysbinary`` fixture is currently only
available in python 3.
.. versionadded:: 3.3 .. versionadded:: 3.3
If the code under test writes non-textual data, you can capture this using If the code under test writes non-textual data, you can capture this using
the ``capfdbinary`` fixture which instead returns ``bytes`` from the ``capfdbinary`` fixture which instead returns ``bytes`` from
the ``readouterr`` method. the ``readouterr`` method. The ``capfdbinary`` fixture operates on the
filedescriptor level.
.. versionadded:: 3.0 .. versionadded:: 3.0

View File

@ -470,6 +470,38 @@ class TestCaptureFixture(object):
""") """)
reprec.assertoutcome(passed=1) reprec.assertoutcome(passed=1)
@pytest.mark.skipif(
sys.version_info < (3,),
reason='only have capsysbinary in python 3',
)
def test_capsysbinary(self, testdir):
reprec = testdir.inline_runsource("""
def test_hello(capsysbinary):
import sys
# some likely un-decodable bytes
sys.stdout.buffer.write(b'\\xfe\\x98\\x20')
out, err = capsysbinary.readouterr()
assert out == b'\\xfe\\x98\\x20'
assert err == b''
""")
reprec.assertoutcome(passed=1)
@pytest.mark.skipif(
sys.version_info >= (3,),
reason='only have capsysbinary in python 3',
)
def test_capsysbinary_forbidden_in_python2(self, testdir):
testdir.makepyfile("""
def test_hello(capsysbinary):
pass
""")
result = testdir.runpytest()
result.stdout.fnmatch_lines([
"*test_hello*",
"*capsysbinary is only supported on python 3*",
"*1 error in*",
])
def test_partial_setup_failure(self, testdir): def test_partial_setup_failure(self, testdir):
p = testdir.makepyfile(""" p = testdir.makepyfile("""
def test_hello(capsys, missingarg): def test_hello(capsys, missingarg):
@ -1233,7 +1265,7 @@ def test_dontreadfrominput_has_encoding(testdir):
reprec.assertoutcome(passed=1) reprec.assertoutcome(passed=1)
def test_pickling_and_unpickling_enocded_file(): def test_pickling_and_unpickling_encoded_file():
# See https://bitbucket.org/pytest-dev/pytest/pull-request/194 # See https://bitbucket.org/pytest-dev/pytest/pull-request/194
# pickle.loads() raises infinite recursion if # pickle.loads() raises infinite recursion if
# EncodedFile.__getattr__ is not implemented properly # EncodedFile.__getattr__ is not implemented properly