Aiding tests with Ludibrio stubs and mocks
In tests we assume some input data and check if the output is equal to what we expect it to be. Sometimes is impossible to set the initial data as the code fetches some data from a third party API, or creates some data on its own (like random data). To aid testing of such code we can use ludibrio. It can mock or stub existing classes or functions making them work as we program it.
Installation is typical - pip install ludibrio. The library allows you to stub objects and define how it should behave. For example random.randint will return a random int from the given range. We don't know what it will be. We can stub it with ludibrio and set one given value it should return. Basing on that we could write a test that could expect a correct output for the stubbed data.
Here is a basic example:import random
def make_magic_number():
number = random.randint(1, 100000)
# some magic we would need to test
return '%010d' % number
from ludibrio import Stub
import random
def make_magic_number():
number = random.randint(1, 100000)
# some magic we would need to test
return '%010d' % number
with Stub() as random.randint:
random.randint(1, 100000) >> 5
print make_magic_number()
The Stub() will cause random.randint(1, 100000) (and only such call) to always return 5. The output starts to be predictable - and testable.
More practical case would be external APIs like JSON, XML or other data fetching and processing. Data fetched from the API changes so we can't test for given data, value in the processed output. With ludibrio we can stub something so that it would return our test data. For example:
# -*- coding: utf-8 -*-
import json
from ludibrio import Stub
import urllib2
url = 'http://www.flickr.com/services/rest/?method=flickr.photos.search&format=json&text=python&api_key=API_KEY'
def get_python_images(url):
handle = urllib2.urlopen(url)
data = handle.read()
# a bit of black magic that could use some tests
data = data.replace('jsonFlickrApi(', '')[:-1]
parsed_data = json.loads(data)
return parsed_data
fake_response = 'jsonFlickrApi({"photos":{"page":1, "pages":666, "perpage":66, "total":"6666", "photo":[{"id":"123", "owner":"1111111@N06", "secret":"abcabc", "server":"1", "farm":1, "title":"Test Python", "ispublic":1, "isfriend":0, "isfamily":0}]}, "stat":"ok"})'
with Stub() as urllib2.urlopen:
urllib2.urlopen(url).read() >> fake_response
print get_python_images(url)
Ludibrio is very handy library. In Django tests it can be an aid in tests of management command or similar code using external data sources (APIs). It also can be useful if we want to test one part of code at a time (when a tested function calls a function that calls a function and so on) stubbing one of called methods, functions etc.
Comment article