From 6a9fd66f6e4445a418c43c92585b9e06d76df4b1 Mon Sep 17 00:00:00 2001 From: Xtreak Date: Wed, 11 Sep 2019 12:02:14 +0100 Subject: [PATCH] bpo-32972: Document IsolatedAsyncioTestCase of unittest module (GH-15878) * Document `unittest.IsolatedAsyncioTestCase` API * Add a simple example with respect to order of evaluation of setup and teardown calls. https://bugs.python.org/issue32972 Automerge-Triggered-By: @asvetlov --- Doc/library/unittest.rst | 76 ++++++++++++++++++++++++++++++++++++++++ Doc/whatsnew/3.8.rst | 26 ++++++++++++++ Misc/NEWS.d/3.8.0b1.rst | 2 +- 3 files changed, 103 insertions(+), 1 deletion(-) diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst index 320d898fc8..8c9affe9db 100644 --- a/Doc/library/unittest.rst +++ b/Doc/library/unittest.rst @@ -1486,8 +1486,84 @@ Test cases .. versionadded:: 3.8 +.. class:: IsolatedAsyncioTestCase(methodName='runTest') + This class provides an API similar to :class:`TestCase` and also accepts + coroutines as test functions. + .. versionadded:: 3.8 + + .. coroutinemethod:: asyncSetUp() + + Method called to prepare the test fixture. This is called after :meth:`setUp`. + This is called immediately before calling the test method; other than + :exc:`AssertionError` or :exc:`SkipTest`, any exception raised by this method + will be considered an error rather than a test failure. The default implementation + does nothing. + + .. coroutinemethod:: asyncTearDown() + + Method called immediately after the test method has been called and the + result recorded. This is called before :meth:`tearDown`. This is called even if + the test method raised an exception, so the implementation in subclasses may need + to be particularly careful about checking internal state. Any exception, other than + :exc:`AssertionError` or :exc:`SkipTest`, raised by this method will be + considered an additional error rather than a test failure (thus increasing + the total number of reported errors). This method will only be called if + the :meth:`asyncSetUp` succeeds, regardless of the outcome of the test method. + The default implementation does nothing. + + .. method:: addAsyncCleanup(function, /, *args, **kwargs) + + This method accepts a coroutine that can be used as a cleanup function. + + .. method:: run(result=None) + + Sets up a new event loop to run the test, collecting the result into + the :class:`TestResult` object passed as *result*. If *result* is + omitted or ``None``, a temporary result object is created (by calling + the :meth:`defaultTestResult` method) and used. The result object is + returned to :meth:`run`'s caller. At the end of the test all the tasks + in the event loop are cancelled. + + + An example illustrating the order:: + + from unittest import IsolatedAsyncioTestCase + + events = [] + + + class Test(IsolatedAsyncioTestCase): + + + def setUp(self): + events.append("setUp") + + async def asyncSetUp(self): + self._async_connection = await AsyncConnection() + events.append("asyncSetUp") + + async def test_response(self): + events.append("test_response") + response = await self._async_connection.get("https://example.com") + self.assertEqual(response.status_code, 200) + self.addAsyncCleanup(self.on_cleanup) + + def tearDown(self): + events.append("tearDown") + + async def asyncTearDown(self): + await self._async_connection.close() + events.append("asyncTearDown") + + async def on_cleanup(self): + events.append("cleanup") + + if __name__ == "__main__": + unittest.main() + + After running the test ``events`` would contain ``["setUp", "asyncSetUp", "test_response", "asyncTearDown", "tearDown", "cleanup"]`` .. class:: FunctionTestCase(testFunc, setUp=None, tearDown=None, description=None) diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst index 2b4eb63d61..07202ea4ff 100644 --- a/Doc/whatsnew/3.8.rst +++ b/Doc/whatsnew/3.8.rst @@ -1111,6 +1111,32 @@ unittest * Several mock assert functions now also print a list of actual calls upon failure. (Contributed by Petter Strandmark in :issue:`35047`.) +* :mod:`unittest` module gained support for coroutines to be used as test cases + with :class:`unittest.IsolatedAsyncioTestCase`. + (Contributed by Andrew Svetlov in :issue:`32972`.) + + Example:: + + import unittest + + + class TestRequest(unittest.IsolatedAsyncioTestCase): + + async def asyncSetUp(self): + self.connection = await AsyncConnection() + + async def test_get(self): + response = await self.connection.get("https://example.com") + self.assertEqual(response.status_code, 200) + + async def asyncTearDown(self): + await self.connection.close() + + + if __name__ == "__main__": + unittest.main() + + venv ---- diff --git a/Misc/NEWS.d/3.8.0b1.rst b/Misc/NEWS.d/3.8.0b1.rst index 84b0350134..43a88a37c5 100644 --- a/Misc/NEWS.d/3.8.0b1.rst +++ b/Misc/NEWS.d/3.8.0b1.rst @@ -808,7 +808,7 @@ detect classes that can be passed to `hex()`, `oct()` and `bin()`. .. nonce: LoeUNh .. section: Library -Implement ``unittest.AsyncTestCase`` to help testing asyncio-based code. +Implement ``unittest.IsolatedAsyncioTestCase`` to help testing asyncio-based code. .. -- 2.40.0