have watched ajdavis@pycon2015 about testing async apps, as below: http://pyvideo.org/video/3419/eventually-correct-testing-async-apps
I have a question about the usage of ExceptionStackContext. In the presentation, it's used as below:
import unittest
from tornado.stack_context import ExceptionStackContext
from tornado.ioloop import IOLoop
class TestAsync(unittest.TestCase):
def test_delay(self):
io_loop = IOLoop.current()
def handle_exception(typ, val, tb):
self.failure = (typ, val, tb)
io_loop.stop()
def done():
self.assertAlmostEqual(time.time() - start, 2)
self.stop()
with ExceptionStackContext(handle_exception):
delay(3, done) # fail the assert
io_loop.start()
run this test, the io_loop will not stop. because the handle_exception is not called.
my async method delay
is:
import threading
import time
def delay(delay_seconds, callback):
def wrap():
time.sleep(delay_seconds)
callback()
t = threading.Thread(target=wrap)
t.daemon = True
t.start()
so i think, it should ExceptionStackContext should wrap the done()
, as below:
def callback():
with ExceptionStackContext(handle_exception):
done()
delay(2, callback)
io_loop.start()
is this the wright way to use ExceptionStackContext?
by the way, ExceptionStackContext in tornado.testing.AsyncTestCase is useless in fact:
def run(self, result=None):
with ExceptionStackContext(self._handle_exception):
super(AsyncTestCase, self).run(result)
super(AsyncTestCase, self).run(result)
does not throw up the AssertException.
StackContexts
are magical: there are many places in Tornado which automatically capture the current StackContext
and resume it later. So when delay()
calls done()
(assuming delay()
is implemented in terms of IOLoop.add_timeout
or otherwise handles StackContext
correctly), the ExceptionStackContext
has been reestablished.
Similarly, even though the ExceptionStackContext
in AsyncTestCase.run()
never directly catches any exceptions, it establishes the "current" StackContext
to be captured anywhere within the test. (That's why it's with ExceptionStackContext
instead of an ordinary try/except
)