Finally, we released pretenders
to the general public, hooray! This is a project I have been developing with my friend and now ex-colleague Alex Couper. It has been a very interesting piece of work, and I am really glad it is out for other test-minded people to enjoy.
Pretenders are fake servers for testing purposes. They are used to mock external servers your code interacts with (such as HTTP APIs or SMTP servers). Mocking is done at the protocol level, making these appropriate for integration test environments, and usable to test applications written in any language (not just Python, which is the language we used to write pretenders
).
As a starter, here are the slides for the lightning talk I gave at PyconUK 2012:
Pretenders
is an open source project. You fill find the source code in Github, and the documentation in readthedocs. As it is just fresh out of the oven, it has some rough edges, mostly around documentation. Feedback and contributions are welcome.
Example usage
In order to use pretenders
in your tests you will have to start a main server we call boss
. The boss will spin off various fakes (pretenders) on demand, and assign them a free port from a configured range. The following examples assume a running pretenders boss
on localhost
at port 8000.
This is a taste of how you would write a test using pretenders to mock an external HTTP API your code depends on:
from pretenders.client.http import HTTPMock # Assume a running boss server at localhost:8000 # Initialise the mock client and clear all responses mock = HTTPMock('localhost', 8000) # For GET requests to /hello reply with a body of 'Hello' mock.when('GET /hello').reply('Hello') # For the next POST or PUT to /somewhere, simulate a BAD REQUEST status code mock.when('(POST|PUT) /somewhere').reply(status=400) # For the next request (any method, any URL) respond with some JSON data mock.reply('{"temperature": 23}', headers={'Content-Type': 'application/json'}) # Point your app to the pretender's URL, and exercise it set_service_url(mock.pretend_access_point) # how you do this is app-specific # ... run stuff # Verify requests your code made r = mock.get_request(0) assert_equal(r.method, 'GET') assert_equal(r.url, '/weather?city=barcelona')
Similarly, a test for an application that sends e-mails, by mocking the SMTP server:
from pretenders.client.smtp import SmtpMock # Create a mock smtp service smtp_mock = SMTPMock('localhost', 8000) # Get the port number that this is faking on and assign as appropriate to the # system being tested (how yo do this will again depend on your application) set_stmp_host_and_port("localhost", smtp_mock.pretend_port) # ...run functionality that should cause an email to be sent # Check that an email was sent email_message = smtp_mock.get_email(0) assert_equals(email_message['Subject'], "Thank you for your order") assert_equals(email_message['From'], "foo@bar.com") assert_equals(email_message['To'], "customer@address.com") assert_true("Your order will be with you" in email_message.content)
There is a bug here!:
from pretenders.http.client import HTTPMock
should be replaced with
from pretenders.client.http import HTTPMock
Thanks for spotting, fixed. We did some refactoring of pretenders to be able to later split client and server, and it never occurred to me to review the blog post.