Python web testing for the Ruby programmer

April 29, 2013 Brandon Liu

Ruby has a couple of well-known libraries for unit testing, mocking and stubbing HTTP interactions. My typical toolset includes RSpec, WebMock and VCR. I had the chance to work on a Python project recently and did some investigation into similar libraries for Python.

General testing libraries

The two most popular python test libraries + runners are py.test and nose. A neat feature of py.test is that is gets by with only the builtin ‘assert’ keyword: the test runner expands assertion failures to show exactly how the assertion failed e.g.:

===================== FAILURES =====================
_____________________ test_web _____________________

    def test_web():
      resp = c.get('/')
>     assert resp.status == '404'
E     assert '200 OK' == '404'
E       - 200 OK
E       + 404

lib/test_snack_overflow.py:9: AssertionError
============= 1 failed in 0.24 seconds =============

One gotcha is that py.test silences stdout by default, so you’ll need to pass the -s flag to see any debugging output.

Test doubles

The mock library can be installed through pip for Python 2 and comes as part of the standard library of Python 3. As an example of mocking out an environment variable using a context manager:

with mock.patch.dict('os.environ', {'APP_NAME': 'HelloWorld'}):
assert app.name = 'HelloWorld'

There’s also a decorator form, nice because it clearly states what modules are being mocked in your tests:

@mock.patch('crazyservice')
def test_nationals_stats(_crazyservice):
_crazyservice.date = "2013-04-06 12:31 AM"

Another gotcha for newcomers to Python testing: not all methods can be replaced at runtime. A good example is stubbing DateTime.now in ruby: the equivalent monkeypatching in python raises:

TypeError: can’t set attributes of built-in/extension type ‘datetime.datetime’

as these methods cannot be replaced in CPython. You’ll need to write a wrapper function and mock that out instead in your tests.

Web testing

The werkzeug WSGI library includes simple utilities to make request testing as easy as with rack-test. Another library I’m a big fan of is HTTPretty, which is similar to Ruby’s WebMock or FakeWeb. Finally, Ruby’s VCR gem is invaluable for recording real HTTP interactions. A port exists on python called vcr.py.

 

About the Author

Biography

Previous
An attitude shift as we approach production
An attitude shift as we approach production

I had the good fortune of attending a workshop about responding to production incidents, led by the folks b...

Next
Less is more in Capybara 2.1
Less is more in Capybara 2.1

One of my favorite changes in Capybara 2.1 is ignoring all hidden elements by default. This could be viewed...