Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Doc/library/unittest.rst
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,14 @@ Test cases
by the test to be propagated to the caller, and can be used to support
running tests under a debugger.

.. method:: runTestMethod(method)

Calls *method* and returns its result. This function is used to execute
all test methods and exists so that subclasses may override it to e.g.
await any possible coroutine returned by the test method.

.. versionadded:: 3.8

.. _assert-methods:

The :class:`TestCase` class provides several assert methods to check for and
Expand Down
9 changes: 8 additions & 1 deletion Lib/unittest/case.py
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,7 @@ def run(self, result=None):
if outcome.success:
outcome.expecting_failure = expecting_failure
with outcome.testPartExecutor(self, isTest=True):
testMethod()
self.runTestMethod(testMethod)
outcome.expecting_failure = False
with outcome.testPartExecutor(self):
self.tearDown()
Expand Down Expand Up @@ -1329,6 +1329,13 @@ def assertNotRegex(self, text, unexpected_regex, msg=None):
msg = self._formatMessage(msg, standardMsg)
raise self.failureException(msg)

def runTestMethod(self, method):
"""Execute the test method.

This method can be overridden in subclasses to (e.g.) run coroutines
in an event loop.
"""
return method()

def _deprecate(original_func):
def deprecated_func(*args, **kwargs):
Expand Down
23 changes: 23 additions & 0 deletions Lib/unittest/test/test_case.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import asyncio
import contextlib
import difflib
import pprint
Expand Down Expand Up @@ -1828,6 +1829,28 @@ def test2(self):
testcase.run()
self.assertEqual(MyException.ninstance, 0)

def test_runTestMethod(self):
# Test that _runTestMethod runs the test method and can be overridden.
class AsyncTestCase(unittest.TestCase):
def __init__(self, method_name):
super().__init__(method_name)
self.test1_called = False

def runTestMethod(self, method):
result = method()
if asyncio.iscoroutine(result):
return asyncio.run(result)
else:
return result

async def test1(self):
await asyncio.sleep(0.0)
self.test1_called = True

testcase = AsyncTestCase('test1')
testcase.run()
self.assertTrue(testcase.test1_called)


if __name__ == "__main__":
unittest.main()
1 change: 1 addition & 0 deletions Misc/ACKS
Original file line number Diff line number Diff line change
Expand Up @@ -1540,6 +1540,7 @@ Daniel Stokes
Michael Stone
Serhiy Storchaka
Ken Stox
Petter Strandmark
Charalampos Stratakis
Dan Stromberg
Donald Stufft
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
``unittest.TestCase`` now has a method ``runTestMethod`` that can be
overridden in subclasses to run coroutine test cases. Patch by Petter
Strandmark.