This project contains extensions to test Tornado apps under pyVows.
To test a tornado app (or handlers) use this context instead of the regular Vows.Context, like this:
import tornado
from tornado_pyvows import TornadoHTTPContext
from pyvows import Vows, expect
class HomeHandler(tornado.web.RequestHandler):
def get(self):
self.write("hello_world")
def post(self):
self.write("hello_world")
@Vows.batch
class SomeVows(TornadoHTTPContext):
def get_app(self):
application = tornado.web.Application([
(r"/", HomeHandler),
])
return application
class HomeUrl(TornadoHTTPContext):
def topic(self):
self.http_client.fetch(self.get_url('/'), self.stop)
response = self.wait()
return response.body
def should_be_hello_world(self, topic):
expect(topic).to_equal("hello_world")
class SameUrl(HomeUrl):
def topic(self):
"""
For convenience you can also use ``get`` and ``post`` to wrap the
calls to the ``http_client``.
"""
response = self.get("/")
return response.body
class SimplePost(HomeUrl):
def topic(self):
response = self.post("/")
return response.body
Each TornadoHTTPContext
provides Tornado's testing methods like
http_client
, get_url
, stop
, wait
, fetch
and others.
If you're developing based on Tornados HTTPClient you can just do that with simple wrappers as seen in client_vows.py
The new IsolatedTornadoHTTPContext
creates a new HTTPServer
that runs the
application. This helps when testing handlers using mocks, e.g.::
@Vows.batch
class ASimpleTestWithAMock(TornadoHTTPContext):
def get_handler_spec(self):
"""..."""
return (r'^/echo$', ExampleHandler)
def get_application_settings(self):
return {'debug': True}
class AndASimpleTestCase(IsolatedTornadoHTTPContext):
def topic(self):
mock = AsyncMock()
mock.return_value = 'mocked echo'
self.get_test_handler().echo = mock
yield (mock, self.fetch('/echo'))
def shouldWorkAsUsual(self, topic):
expect(topic).Not.to_be_an_error()
def shouldReturnTheExpectedTopic(self, topic):
(_, resp) = topic
expect(resp.body).to_equal('mocked echo')
class ThatBlahsBlahs(TornadoHTTPContext):
def topic(self, topic):
yield (topic, self.fetch('/echo'))
def shouldReturnTheExpectedTopic(self, topic):
(_, resp) = topic
expect(resp.body).to_equal('mocked echo')
class ThatHasNoSideEffects(IsolatedTornadoHTTPContext):
def topic(self):
yield self.fetch('/echo')
def shouldWorkAsUsual(self, topic):
expect(topic).Not.to_be_an_error()
def shouldReturnTheExpectedTopic(self, resp):
expect(resp.body).to_equal('echo')
If you want to test a tornado based app without the HTTP overhead you may also
use the TornadoContext
:
def asyncMethod(callback):
callback("Pseudo Async Result")
@Vows.batch
class AsyncVows(TornadoContext):
class CallbacksShouldWork(TornadoContext):
def topic(self):
self.io_loop = self.get_new_ioloop()
self.io_loop.add_callback(lambda: asyncMethod(self.stop))
return self.wait()
def and_have_the_correct_result(self, topic):
expect(topic).to_equal("Pseudo Async Result")
The above example creates a new IOLoop for every test, which is nice. Some libraries add
callbacks to the IOLoop.instance()
singleton, such as tornado.httpclient.AsyncHTTPClient
.
These libraries can be tested by overloading the get_new_ioloop
method to return the
IOLoop.instance()
singleton.
@Vows.batch
class AsyncVows(TornadoContext):
class PyVowsSiteVows(TornadoContext):
def get_new_ioloop(self):
return IOLoop.instance()
def topic(self):
self.io_loop = self.get_new_ioloop()
http_client = AsyncHTTPClient()
http_client.fetch("http://heynemann.github.com/pyvows/",
self.stop)
return self.wait()
def to_be_about_asynchronous_testing(self, topic):
expect(topic.body).to_include('Asynchronous BDD for Python')
Contributions are very welcome. To contribute fork it and create a pull request.
The team behind Tornado_pyVows (in order of joining the project):
- Rafael Carício @rafaelcaricio
- Bernardo Heynemann @heynemann
- Daniel Truemper @truemped
- Norman Rosner @rosner
- Guilherme Souza @guilhermef
- tarnacious @tarnacious
- Damien Hardy @dhardy92
- W. Trevor King @wking
- Others