self.wait(timeout=0.15)
+class AsyncTestCaseWrapperTest(unittest.TestCase):
+ def test_undecorated_generator(self):
+ class Test(AsyncTestCase):
+ def test_gen(self):
+ yield
+ test = Test('test_gen')
+ result = unittest.TestResult()
+ test.run(result)
+ self.assertEqual(len(result.errors), 1)
+ self.assertIn("should be decorated", result.errors[0][1])
+
+ def test_undecorated_generator_with_skip(self):
+ class Test(AsyncTestCase):
+ @unittest.skip("don't run this")
+ def test_gen(self):
+ yield
+ test = Test('test_gen')
+ result = unittest.TestResult()
+ test.run(result)
+ self.assertEqual(len(result.errors), 0)
+ self.assertEqual(len(result.skipped), 1)
+
+ def test_other_return(self):
+ class Test(AsyncTestCase):
+ def test_other_return(self):
+ return 42
+ test = Test('test_other_return')
+ result = unittest.TestResult()
+ test.run(result)
+ self.assertEqual(len(result.errors), 1)
+ self.assertIn("Return value from test method ignored", result.errors[0][1])
+
+
class SetUpTearDownTest(unittest.TestCase):
def test_set_up_tear_down(self):
"""
import signal
import socket
import sys
+import types
try:
from cStringIO import StringIO # py2
return 5
+class _TestMethodWrapper(object):
+ """Wraps a test method to raise an error if it returns a value.
+
+ This is mainly used to detect undecorated generators (if a test
+ method yields it must use a decorator to consume the generator),
+ but will also detect other kinds of return values (these are not
+ necessarily errors, but we alert anyway since there is no good
+ reason to return a value from a test.
+ """
+ def __init__(self, orig_method):
+ self.orig_method = orig_method
+
+ def __call__(self):
+ result = self.orig_method()
+ if isinstance(result, types.GeneratorType):
+ raise TypeError("Generator test methods should be decorated with "
+ "tornado.testing.gen_test")
+ elif result is not None:
+ raise ValueError("Return value from test method ignored: %r" %
+ result)
+
+ def __getattr__(self, name):
+ """Proxy all unknown attributes to the original method.
+
+ This is important for some of the decorators in the `unittest`
+ module, such as `unittest.skipIf`.
+ """
+ return getattr(self.orig_method, name)
+
class AsyncTestCase(unittest.TestCase):
"""`~unittest.TestCase` subclass for testing `.IOLoop`-based
asynchronous code.
self.assertIn("FriendFeed", response.body)
self.stop()
"""
- def __init__(self, *args, **kwargs):
- super(AsyncTestCase, self).__init__(*args, **kwargs)
+ def __init__(self, methodName='runTest', **kwargs):
+ super(AsyncTestCase, self).__init__(methodName, **kwargs)
self.__stopped = False
self.__running = False
self.__failure = None
self.__stop_args = None
self.__timeout = None
+ # It's easy to forget the @gen_test decorator, but if you do
+ # the test will silently be ignored because nothing will consume
+ # the generator. Replace the test method with a wrapper that will
+ # make sure it's not an undecorated generator.
+ setattr(self, methodName, _TestMethodWrapper(getattr(self, methodName)))
+
def setUp(self):
super(AsyncTestCase, self).setUp()
self.io_loop = self.get_new_ioloop()