Last Updated: February 25, 2016
·
3.067K
· sigmavirus24

Testing with Betamax

If you do any amount of work in python with requests and value testing, you are either mocking out the library or hitting external links frequently. While testing my library which wraps an API, I was mocking out responses with recorded responses.

For example, I would have a file with only the JSON returned by the API and every class containing tests had to inherit from a specific object. This object performed a lot of set up before tests could be run:

  • Requests would be stubbed out and configured to return a specific response
  • Information was collected so assertions could be made
  • Poorly faked responses were created

One such test might be as simple as:

def test_unstar(self):
    self.response('', 204)
    self.delete(self.api)
    self.conf = {}

    self.assertRaises(self.gist.unstar)

    self.not_called()
    self.login()
    assert self.gist.unstar() is True
    self.mock_assertions()

or as complex as this test.

Recently I began working on a fairly large Sinatra application that uses VCR to record requests to other services. This inspired me to create Betamax and start immediately using it to test github3.py. Now my integration tests are all as simple as:

def test_iter_releases(self):
    """Test the ability to iterate over releases on a repository."""
    cassette_name = self.cassette_name('iter_releases')
    with self.recorder.use_cassette(cassette_name):
        repository = self.gh.repository('sigmavirus24', 'github3.py')
        assert repository is not None
        for release in repository.iter_releases():
            assert isinstance(release, github3.repos.release.Release)

There's a little bit of work to set up self.recorder which is just the instance of Betamax wrapping my Requests Session and all of the interactions are recorded for me and replayed later.

The set up for these tests is a short 30 lines.

To read more about Betamax, have a look at the documentation.