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: We get a random number and then return it in a given format (assume it's something complex). As the number is random it's hart do test it. But we can use ludibrio like so:
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:In this example urllib2.urlopen will not call the Flick API but it will return our test data set. As it's fixed we can test if the parsed output contains what it should contain.
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.