tornado.testing — Unit testing support for asynchronous code¶
Support classes for automated testing.
- AsyncTestCase and AsyncHTTPTestCase: Subclasses of unittest.TestCasewith additional support for testing asynchronous (IOLoop based) code.
- ExpectLog and LogTrapTestCase: Make test logs less spammy.
- main(): A simple test runner (wrapper around unittest.main()) with supportfor the tornado.autoreload module to rerun the tests when code changes.
Asynchronous test cases¶
- class
tornado.testing.
AsyncTestCase
(methodName='runTest')[源代码]¶ TestCase
subclass for testingIOLoop
-basedasynchronous code.
The unittest framework is synchronous, so the test must becomplete by the time the test method returns. This means thatasynchronous code cannot be used in quite the same way as usual.To write test functions that use the sameyield
-based patternsused with thetornado.gen
module, decorate your test methodswithtornado.testing.gen_test
instead oftornado.gen.coroutine
. This class also provides thestop()
andwait()
methods for a more manual style of testing. The testmethod itself must callself.wait()
, and asynchronouscallbacks should callself.stop()
to signal completion.
By default, a newIOLoop
is constructed for each test and is availableasself.ioloop
. ThisIOLoop
should be used in the construction ofHTTP clients/servers, etc. If the code being tested requires aglobalIOLoop
, subclasses should overrideget_new_ioloop
to return it.
TheIOLoop
‘sstart
andstop
methods should not becalled directly. Instead, useself.stop
andself.wait
. Arguments passed toself.stop
are returned fromself.wait
. It is possible to have multiplewait
/stop
cycles in the same test.
Example:- # This test uses coroutine style.
class MyTestCase(AsyncTestCase):
@tornado.testing.gen_test
def test_http_fetch(self):
client = AsyncHTTPClient(self.io_loop)
response = yield client.fetch("http://www.tornadoweb.org")
# Test contents of response
self.assertIn("FriendFeed", response.body)
# This test uses argument passing between self.stop and self.wait.
class MyTestCase2(AsyncTestCase):
def test_http_fetch(self):
client = AsyncHTTPClient(self.io_loop)
client.fetch("http://www.tornadoweb.org/", self.stop)
response = self.wait()
# Test contents of response
self.assertIn("FriendFeed", response.body)
# This test uses an explicit callback-based style.
class MyTestCase3(AsyncTestCase):
def test_http_fetch(self):
client = AsyncHTTPClient(self.io_loop)
client.fetch("http://www.tornadoweb.org/", self.handle_fetch)
self.wait()
def handle_fetch(self, response):
# Test contents of response (failures and exceptions here
# will cause self.wait() to throw an exception and end the
# test).
# Exceptions thrown here are magically propagated to
# self.wait() in test_http_fetch() via stack_context.
self.assertIn("FriendFeed", response.body)
self.stop()
get_new_ioloop
()[源代码]¶
Creates a newIOLoop
for this test. May be overridden insubclasses for tests that require a specificIOLoop
(usuallythe singletonIOLoop.instance()
).
stop
(__arg=None, **kwargs)[源代码]¶
Stops theIOLoop
, causing one pending (or future) call towait()
to return.
Keyword arguments or a single positional argument passed tostop()
aresaved and will be returned bywait()
.
wait
(condition=None, timeout=None)[源代码]¶
Runs theIOLoop
until stop is called or timeout has passed.
In the event of a timeout, an exception will be thrown. Thedefault timeout is 5 seconds; it may be overridden with atimeout
keyword argument or globally with theASYNCTEST_TIMEOUT
environment variable.
Ifcondition
is not None, theIOLoop
will be restartedafterstop()
untilcondition()
returns true.
在 3.1 版更改: Added theASYNC_TEST_TIMEOUT
environment variable.
- # This test uses coroutine style.
- _class
tornado.testing.
AsyncHTTPTestCase
(methodName='runTest')[源代码]¶
A test case that starts up an HTTP server.
Subclasses must overrideget_app()
, which returns thetornado.web.Application
(or otherHTTPServer
callback) to be tested.Tests will typically use the providedself.httpclient
to fetchURLs from this server.
Example, assuming the “Hello, world” example from the user guide is inhello.py
:- import hello
class TestHelloApp(AsyncHTTPTestCase):
def get_app(self):
return hello.make_app()
def test_homepage(self):
response = self.fetch('/')
self.assertEqual(response.code, 200)
self.assertEqual(response.body, 'Hello, world')
That call toself.fetch()
is equivalent to- self.http_client.fetch(self.get_url('/'), self.stop)
response = self.wait()
which illustrates how AsyncTestCase can turn an asynchronous operation,likehttp_client.fetch()
, into a synchronous operation. If you needto do other asynchronous operations in tests, you’ll probably need to usestop()
andwait()
yourself.fetch
(_path, **kwargs)[源代码]¶
Convenience method to synchronously fetch a url.
The given path will be appended to the local server’s host andport. Any additional kwargs will be passed directly toAsyncHTTPClient.fetch
(and so could be used to passmethod="POST"
,body="…"
, etc).
getapp
()[源代码]¶
Should be overridden by subclasses to return atornado.web.Application
or otherHTTPServer
callback.
- import hello
- class
tornado.testing.
AsyncHTTPSTestCase
(methodName='runTest')[源代码]¶
A test case that starts an HTTPS server.
Interface is generally the same asAsyncHTTPTestCase
.
tornado.testing.
gen_test
(_func=None, timeout=None)[源代码]¶
Testing equivalent of@gen.coroutine
, to be applied to test methods.@gen.coroutine
cannot be used on tests because theIOLoop
is notalready running.@gen_test
should be applied to test methodson subclasses ofAsyncTestCase
.
Example:- class MyTest(AsyncHTTPTestCase):
@gen_test
def test_something(self):
response = yield gen.Task(self.fetch('/'))
By default,@gen_test
times out after 5 seconds. The timeout may beoverridden globally with theASYNC_TEST_TIMEOUT
environment variable,or for each test with thetimeout
keyword argument:- class MyTest(AsyncHTTPTestCase):
@gen_test(timeout=10)
def test_something_slow(self):
response = yield gen.Task(self.fetch('/'))
3.1 新版功能: Thetimeout
argument andASYNC_TEST_TIMEOUT
environmentvariable.
在 4.0 版更改: The wrapper now passes alongargs, *kwargs
so it can be usedon functions with arguments.- class MyTest(AsyncHTTPTestCase):
Controlling log output¶
- class
tornado.testing.
ExpectLog
(logger, regex, required=True)[源代码]¶
Context manager to capture and suppress expected log output.
Useful to make tests of error conditions less noisy, while stillleaving unexpected log entries visible. Not thread safe.
The attributeloggedstack
is set to true if any exceptionstack trace was logged.
Usage:- with ExpectLog('tornado.application', "Uncaught exception"):
error_response = self.fetch("/some_page")
在 4.3 版更改: Added thelogged_stack
attribute.
Constructs an ExpectLog context manager.
|参数:
|——-
|
- logger – Logger object (or name of logger) to watch. Passan empty string to watch the root logger.
- regex – Regular expression to match. Any log entries onthe specified logger that match this regex will be suppressed.
- required – If true, an exeption will be raised if the end ofthe with statement is reached without matching any log entries.- with ExpectLog('tornado.application', "Uncaught exception"):
- _class
tornado.testing.
LogTrapTestCase
(methodName='runTest')[源代码]¶
A test case that captures and discards all logging outputif the test passes.
Some libraries can produce a lot of logging output even whenthe test succeeds, so this class can be useful to minimize the noise.Simply use it as a base class for your test case. It is safe to combinewith AsyncTestCase via multiple inheritance(class MyTestCase(AsyncHTTPTestCase, LogTrapTestCase):
)
This class assumes that only one log handler is configured andthat it is aStreamHandler
. This is true for bothlogging.basicConfig
and the “pretty logging” configured bytornado.options
. It is not compatible with other log bufferingmechanisms, such as those provided by some test runners.
4.1 版后已移除: Use the unittest module’s—buffer
option instead, orExpectLog
.
Create an instance of the class that will use the named testmethod when executed. Raises a ValueError if the instance doesnot have a method with the specified name.
Test runner¶
tornado.testing.
main
(**kwargs)[源代码]¶
A simple test runner.
This test runner is essentially equivalent tounittest.main
fromthe standard library, but adds support for tornado-style optionparsing and log formatting.
The easiest way to run a test is via the command line:- python -m tornado.testing tornado.test.stack_context_test
See the standard library unittest module for ways in which tests canbe specified.
Projects with many tests may wish to define a test script liketornado/test/runtests.py
. This script should define a methodall()
which returns a test suite and then calltornado.testing.main()
. Note that even when a test script isused, theall()
test suite may be overridden by naming asingle test on the command line:- # Runs all tests
python -m tornado.test.runtests
# Runs one test
python -m tornado.test.runtests tornado.test.stack_context_test
Additional keyword arguments passed through tounittest.main()
.For example, usetornado.testing.main(verbosity=2)
to show many test details as they are run.See http://docs.python.org/library/unittest.html#unittest.mainfor full argument list.- python -m tornado.testing tornado.test.stack_context_test
Helper functions¶
tornado.testing.
bindunused_port
(_reuse_port=False)[源代码]¶
Binds a server socket to an available port on localhost.
Returns a tuple (socket, port).
在 4.4 版更改: Always binds to127.0.0.1
without resolving the namelocalhost
.
tornado.testing.
get_unused_port
()[源代码]¶
Returns a (hopefully) unused port number.
This function does not guarantee that the port it returns is available,only that a series of get_unused_port calls in a single process returndistinct ports.
Use 版后已移除: bind_unused_port instead, which is guaranteed to find an unused port.
tornado.testing.
get_async_test_timeout
()[源代码]¶
Get the global timeout setting for async tests.
Returns a float, the timeout in seconds.
3.1 新版功能.
原文:
https://tornado-zh-cn.readthedocs.io/zh_CN/latest/testing.html