bpo-45238: Fix unittest.IsolatedAsyncioTestCase.debug() (GH-28449)

It runs now asynchronous methods and callbacks.

If it fails, doCleanups() can be called for cleaning up.
This commit is contained in:
Serhiy Storchaka 2021-09-22 18:43:23 +03:00 committed by GitHub
parent 58f8adfda3
commit ecb6922ff2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 180 additions and 65 deletions

View file

@ -1,5 +1,10 @@
import asyncio
import unittest
from test import support
class MyException(Exception):
pass
def tearDownModule():
@ -7,9 +12,14 @@ def tearDownModule():
class TestAsyncCase(unittest.TestCase):
def test_full_cycle(self):
events = []
maxDiff = None
def tearDown(self):
# Ensure that IsolatedAsyncioTestCase instances are destroyed before
# starting a new event loop
support.gc_collect()
def test_full_cycle(self):
class Test(unittest.IsolatedAsyncioTestCase):
def setUp(self):
self.assertEqual(events, [])
@ -18,12 +28,13 @@ class TestAsyncCase(unittest.TestCase):
async def asyncSetUp(self):
self.assertEqual(events, ['setUp'])
events.append('asyncSetUp')
self.addAsyncCleanup(self.on_cleanup1)
async def test_func(self):
self.assertEqual(events, ['setUp',
'asyncSetUp'])
events.append('test')
self.addAsyncCleanup(self.on_cleanup)
self.addAsyncCleanup(self.on_cleanup2)
async def asyncTearDown(self):
self.assertEqual(events, ['setUp',
@ -38,34 +49,48 @@ class TestAsyncCase(unittest.TestCase):
'asyncTearDown'])
events.append('tearDown')
async def on_cleanup(self):
async def on_cleanup1(self):
self.assertEqual(events, ['setUp',
'asyncSetUp',
'test',
'asyncTearDown',
'tearDown',
'cleanup2'])
events.append('cleanup1')
async def on_cleanup2(self):
self.assertEqual(events, ['setUp',
'asyncSetUp',
'test',
'asyncTearDown',
'tearDown'])
events.append('cleanup')
events.append('cleanup2')
events = []
test = Test("test_func")
test.run()
self.assertEqual(events, ['setUp',
'asyncSetUp',
'test',
'asyncTearDown',
'tearDown',
'cleanup'])
result = test.run()
self.assertEqual(result.errors, [])
self.assertEqual(result.failures, [])
expected = ['setUp', 'asyncSetUp', 'test',
'asyncTearDown', 'tearDown', 'cleanup2', 'cleanup1']
self.assertEqual(events, expected)
events = []
test = Test("test_func")
test.debug()
self.assertEqual(events, expected)
test.doCleanups()
self.assertEqual(events, expected)
def test_exception_in_setup(self):
events = []
class Test(unittest.IsolatedAsyncioTestCase):
async def asyncSetUp(self):
events.append('asyncSetUp')
raise Exception()
self.addAsyncCleanup(self.on_cleanup)
raise MyException()
async def test_func(self):
events.append('test')
self.addAsyncCleanup(self.on_cleanup)
async def asyncTearDown(self):
events.append('asyncTearDown')
@ -74,35 +99,26 @@ class TestAsyncCase(unittest.TestCase):
events.append('cleanup')
events = []
test = Test("test_func")
test.run()
result = test.run()
self.assertEqual(events, ['asyncSetUp', 'cleanup'])
self.assertIs(result.errors[0][0], test)
self.assertIn('MyException', result.errors[0][1])
events = []
test = Test("test_func")
try:
test.debug()
except MyException:
pass
else:
self.fail('Expected a MyException exception')
self.assertEqual(events, ['asyncSetUp'])
test.doCleanups()
self.assertEqual(events, ['asyncSetUp', 'cleanup'])
def test_exception_in_test(self):
events = []
class Test(unittest.IsolatedAsyncioTestCase):
async def asyncSetUp(self):
events.append('asyncSetUp')
async def test_func(self):
events.append('test')
raise Exception()
self.addAsyncCleanup(self.on_cleanup)
async def asyncTearDown(self):
events.append('asyncTearDown')
async def on_cleanup(self):
events.append('cleanup')
test = Test("test_func")
test.run()
self.assertEqual(events, ['asyncSetUp', 'test', 'asyncTearDown'])
def test_exception_in_test_after_adding_cleanup(self):
events = []
class Test(unittest.IsolatedAsyncioTestCase):
async def asyncSetUp(self):
events.append('asyncSetUp')
@ -110,7 +126,7 @@ class TestAsyncCase(unittest.TestCase):
async def test_func(self):
events.append('test')
self.addAsyncCleanup(self.on_cleanup)
raise Exception()
raise MyException()
async def asyncTearDown(self):
events.append('asyncTearDown')
@ -118,13 +134,26 @@ class TestAsyncCase(unittest.TestCase):
async def on_cleanup(self):
events.append('cleanup')
events = []
test = Test("test_func")
test.run()
result = test.run()
self.assertEqual(events, ['asyncSetUp', 'test', 'asyncTearDown', 'cleanup'])
self.assertIs(result.errors[0][0], test)
self.assertIn('MyException', result.errors[0][1])
events = []
test = Test("test_func")
try:
test.debug()
except MyException:
pass
else:
self.fail('Expected a MyException exception')
self.assertEqual(events, ['asyncSetUp', 'test'])
test.doCleanups()
self.assertEqual(events, ['asyncSetUp', 'test', 'cleanup'])
def test_exception_in_tear_down(self):
events = []
class Test(unittest.IsolatedAsyncioTestCase):
async def asyncSetUp(self):
events.append('asyncSetUp')
@ -135,37 +164,70 @@ class TestAsyncCase(unittest.TestCase):
async def asyncTearDown(self):
events.append('asyncTearDown')
raise Exception()
raise MyException()
async def on_cleanup(self):
events.append('cleanup')
events = []
test = Test("test_func")
test.run()
result = test.run()
self.assertEqual(events, ['asyncSetUp', 'test', 'asyncTearDown', 'cleanup'])
self.assertIs(result.errors[0][0], test)
self.assertIn('MyException', result.errors[0][1])
events = []
test = Test("test_func")
try:
test.debug()
except MyException:
pass
else:
self.fail('Expected a MyException exception')
self.assertEqual(events, ['asyncSetUp', 'test', 'asyncTearDown'])
test.doCleanups()
self.assertEqual(events, ['asyncSetUp', 'test', 'asyncTearDown', 'cleanup'])
def test_exception_in_tear_clean_up(self):
events = []
class Test(unittest.IsolatedAsyncioTestCase):
async def asyncSetUp(self):
events.append('asyncSetUp')
async def test_func(self):
events.append('test')
self.addAsyncCleanup(self.on_cleanup)
self.addAsyncCleanup(self.on_cleanup1)
self.addAsyncCleanup(self.on_cleanup2)
async def asyncTearDown(self):
events.append('asyncTearDown')
async def on_cleanup(self):
events.append('cleanup')
raise Exception()
async def on_cleanup1(self):
events.append('cleanup1')
raise MyException('some error')
async def on_cleanup2(self):
events.append('cleanup2')
raise MyException('other error')
events = []
test = Test("test_func")
test.run()
self.assertEqual(events, ['asyncSetUp', 'test', 'asyncTearDown', 'cleanup'])
result = test.run()
self.assertEqual(events, ['asyncSetUp', 'test', 'asyncTearDown', 'cleanup2', 'cleanup1'])
self.assertIs(result.errors[0][0], test)
self.assertIn('MyException: other error', result.errors[0][1])
self.assertIn('MyException: some error', result.errors[1][1])
events = []
test = Test("test_func")
try:
test.debug()
except MyException:
pass
else:
self.fail('Expected a MyException exception')
self.assertEqual(events, ['asyncSetUp', 'test', 'asyncTearDown', 'cleanup2'])
test.doCleanups()
self.assertEqual(events, ['asyncSetUp', 'test', 'asyncTearDown', 'cleanup2', 'cleanup1'])
def test_deprecation_of_return_val_from_test(self):
# Issue 41322 - deprecate return of value!=None from a test
@ -255,7 +317,49 @@ class TestAsyncCase(unittest.TestCase):
output = test.run()
self.assertTrue(cancelled)
def test_debug_cleanup_same_loop(self):
class Test(unittest.IsolatedAsyncioTestCase):
async def asyncSetUp(self):
async def coro():
await asyncio.sleep(0)
fut = asyncio.ensure_future(coro())
self.addAsyncCleanup(self.cleanup, fut)
events.append('asyncSetUp')
async def test_func(self):
events.append('test')
raise MyException()
async def asyncTearDown(self):
events.append('asyncTearDown')
async def cleanup(self, fut):
try:
# Raises an exception if in different loop
await asyncio.wait([fut])
events.append('cleanup')
except:
import traceback
traceback.print_exc()
raise
events = []
test = Test("test_func")
result = test.run()
self.assertEqual(events, ['asyncSetUp', 'test', 'asyncTearDown', 'cleanup'])
self.assertIn('MyException', result.errors[0][1])
events = []
test = Test("test_func")
try:
test.debug()
except MyException:
pass
else:
self.fail('Expected a MyException exception')
self.assertEqual(events, ['asyncSetUp', 'test'])
test.doCleanups()
self.assertEqual(events, ['asyncSetUp', 'test', 'cleanup'])
if __name__ == "__main__":