Honour stdout on TestProgram more fully.
We were failing to pass it into the runner, and this causes hilarity for child runners which then end up with sys.stdout in their test suite, rather than their stub streams. Change-Id: I19984102547f92493f330059928f7e0b3897c38c
This commit is contained in:
6
NEWS
6
NEWS
@@ -10,6 +10,12 @@ NEXT
|
|||||||
Changes
|
Changes
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
* ``stdout`` is now correctly honoured on ``run.TestProgram`` - before the
|
||||||
|
runner objects would be created with no stdout parameter. If construction
|
||||||
|
fails, the previous parameter list is attempted, permitting compatibility
|
||||||
|
with Runner classes that don't accept stdout as a parameter.
|
||||||
|
(Robert Collins)
|
||||||
|
|
||||||
* The ``ExtendedToStreamDecorator`` now handles content objects with one less
|
* The ``ExtendedToStreamDecorator`` now handles content objects with one less
|
||||||
packet - the last packet of the source content is sent with EOF set rather
|
packet - the last packet of the source content is sent with EOF set rather
|
||||||
than an empty packet with EOF set being sent after the last packet of the
|
than an empty packet with EOF set being sent after the last packet of the
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class TestCommand(Command):
|
|||||||
|
|
||||||
def __init__(self, dist):
|
def __init__(self, dist):
|
||||||
Command.__init__(self, dist)
|
Command.__init__(self, dist)
|
||||||
self.runner = TestToolsTestRunner(sys.stdout)
|
self.runner = TestToolsTestRunner(stdout=sys.stdout)
|
||||||
|
|
||||||
|
|
||||||
def initialize_options(self):
|
def initialize_options(self):
|
||||||
|
|||||||
@@ -73,6 +73,8 @@ class TestToolsTestRunner(object):
|
|||||||
:param stdout: Stream to use for stdout.
|
:param stdout: Stream to use for stdout.
|
||||||
"""
|
"""
|
||||||
self.failfast = failfast
|
self.failfast = failfast
|
||||||
|
if stdout is None:
|
||||||
|
stdout = sys.stdout
|
||||||
self.stdout = stdout
|
self.stdout = stdout
|
||||||
|
|
||||||
def list(self, test):
|
def list(self, test):
|
||||||
@@ -89,7 +91,7 @@ class TestToolsTestRunner(object):
|
|||||||
def run(self, test):
|
def run(self, test):
|
||||||
"Run the given test case or test suite."
|
"Run the given test case or test suite."
|
||||||
result = TextTestResult(
|
result = TextTestResult(
|
||||||
unicode_output_stream(sys.stdout), failfast=self.failfast)
|
unicode_output_stream(self.stdout), failfast=self.failfast)
|
||||||
result.startTestRun()
|
result.startTestRun()
|
||||||
try:
|
try:
|
||||||
return test.run(result)
|
return test.run(result)
|
||||||
@@ -185,6 +187,7 @@ class TestProgram(object):
|
|||||||
argv = sys.argv
|
argv = sys.argv
|
||||||
if stdout is None:
|
if stdout is None:
|
||||||
stdout = sys.stdout
|
stdout = sys.stdout
|
||||||
|
self.stdout = stdout
|
||||||
|
|
||||||
self.exit = exit
|
self.exit = exit
|
||||||
self.failfast = failfast
|
self.failfast = failfast
|
||||||
@@ -224,7 +227,7 @@ class TestProgram(object):
|
|||||||
runner.list(self.test)
|
runner.list(self.test)
|
||||||
else:
|
else:
|
||||||
for test in iterate_tests(self.test):
|
for test in iterate_tests(self.test):
|
||||||
stdout.write('%s\n' % test.id())
|
self.stdout.write('%s\n' % test.id())
|
||||||
|
|
||||||
def usageExit(self, msg=None):
|
def usageExit(self, msg=None):
|
||||||
if msg:
|
if msg:
|
||||||
@@ -375,12 +378,20 @@ class TestProgram(object):
|
|||||||
def _get_runner(self):
|
def _get_runner(self):
|
||||||
if self.testRunner is None:
|
if self.testRunner is None:
|
||||||
self.testRunner = TestToolsTestRunner
|
self.testRunner = TestToolsTestRunner
|
||||||
|
try:
|
||||||
|
testRunner = self.testRunner(verbosity=self.verbosity,
|
||||||
|
failfast=self.failfast,
|
||||||
|
buffer=self.buffer,
|
||||||
|
stdout=self.stdout)
|
||||||
|
except TypeError:
|
||||||
|
# didn't accept the verbosity, buffer, failfast or stdout arguments
|
||||||
|
# Try with the prior contract
|
||||||
try:
|
try:
|
||||||
testRunner = self.testRunner(verbosity=self.verbosity,
|
testRunner = self.testRunner(verbosity=self.verbosity,
|
||||||
failfast=self.failfast,
|
failfast=self.failfast,
|
||||||
buffer=self.buffer)
|
buffer=self.buffer)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
# didn't accept the verbosity, buffer or failfast arguments
|
# Now try calling it with defaults
|
||||||
try:
|
try:
|
||||||
testRunner = self.testRunner()
|
testRunner = self.testRunner()
|
||||||
except TypeError:
|
except TypeError:
|
||||||
|
|||||||
@@ -61,8 +61,8 @@ class TestCommandTest(TestCase):
|
|||||||
dist.cmdclass = {'test': TestCommand}
|
dist.cmdclass = {'test': TestCommand}
|
||||||
dist.command_options = {
|
dist.command_options = {
|
||||||
'test': {'test_module': ('command line', 'testtools.runexample')}}
|
'test': {'test_module': ('command line', 'testtools.runexample')}}
|
||||||
cmd = dist.reinitialize_command('test')
|
|
||||||
with fixtures.MonkeyPatch('sys.stdout', stdout.stream):
|
with fixtures.MonkeyPatch('sys.stdout', stdout.stream):
|
||||||
|
cmd = dist.reinitialize_command('test')
|
||||||
dist.run_command('test')
|
dist.run_command('test')
|
||||||
self.assertThat(
|
self.assertThat(
|
||||||
stdout.getDetails()['stdout'].as_text(),
|
stdout.getDetails()['stdout'].as_text(),
|
||||||
@@ -83,8 +83,8 @@ OK
|
|||||||
'test': {
|
'test': {
|
||||||
'test_suite': (
|
'test_suite': (
|
||||||
'command line', 'testtools.runexample.test_suite')}}
|
'command line', 'testtools.runexample.test_suite')}}
|
||||||
cmd = dist.reinitialize_command('test')
|
|
||||||
with fixtures.MonkeyPatch('sys.stdout', stdout.stream):
|
with fixtures.MonkeyPatch('sys.stdout', stdout.stream):
|
||||||
|
cmd = dist.reinitialize_command('test')
|
||||||
dist.run_command('test')
|
dist.run_command('test')
|
||||||
self.assertThat(
|
self.assertThat(
|
||||||
stdout.getDetails()['stdout'].as_text(),
|
stdout.getDetails()['stdout'].as_text(),
|
||||||
|
|||||||
@@ -13,9 +13,13 @@ import testtools
|
|||||||
from testtools import TestCase, run
|
from testtools import TestCase, run
|
||||||
from testtools.compat import (
|
from testtools.compat import (
|
||||||
_b,
|
_b,
|
||||||
|
_u,
|
||||||
StringIO,
|
StringIO,
|
||||||
)
|
)
|
||||||
from testtools.matchers import Contains
|
from testtools.matchers import (
|
||||||
|
Contains,
|
||||||
|
MatchesRegex,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if fixtures:
|
if fixtures:
|
||||||
@@ -235,12 +239,27 @@ testtools.resourceexample.TestFoo.test_foo
|
|||||||
self.fail('a')
|
self.fail('a')
|
||||||
def test_b(self):
|
def test_b(self):
|
||||||
self.fail('b')
|
self.fail('b')
|
||||||
runner = run.TestToolsTestRunner(failfast=True)
|
|
||||||
with fixtures.MonkeyPatch('sys.stdout', stdout.stream):
|
with fixtures.MonkeyPatch('sys.stdout', stdout.stream):
|
||||||
|
runner = run.TestToolsTestRunner(failfast=True)
|
||||||
runner.run(TestSuite([Failing('test_a'), Failing('test_b')]))
|
runner.run(TestSuite([Failing('test_a'), Failing('test_b')]))
|
||||||
self.assertThat(
|
self.assertThat(
|
||||||
stdout.getDetails()['stdout'].as_text(), Contains('Ran 1 test'))
|
stdout.getDetails()['stdout'].as_text(), Contains('Ran 1 test'))
|
||||||
|
|
||||||
|
def test_stdout_honoured(self):
|
||||||
|
self.useFixture(SampleTestFixture())
|
||||||
|
tests = []
|
||||||
|
out = StringIO()
|
||||||
|
exc = self.assertRaises(SystemExit, run.main,
|
||||||
|
argv=['prog', 'testtools.runexample.test_suite'],
|
||||||
|
stdout=out)
|
||||||
|
self.assertEqual((0,), exc.args)
|
||||||
|
self.assertThat(
|
||||||
|
out.getvalue(),
|
||||||
|
MatchesRegex(_u("""Tests running...
|
||||||
|
|
||||||
|
Ran 2 tests in \\d.\\d\\d\\ds
|
||||||
|
OK
|
||||||
|
""")))
|
||||||
|
|
||||||
|
|
||||||
def test_suite():
|
def test_suite():
|
||||||
|
|||||||
Reference in New Issue
Block a user