Yesterday I was working on a script that should run forever, or at least until the user stops it. The library behind it was already tested except for this little function:
this is the entry point of my library. I have an executable that just parses a directory name from command line and call this function. It’s purpose it to collect all files from a directory, filter based on some rules, and publish the file names in a queue which will be consumed by another script. It runs forever because newly created files are detected and collected too.
Anyway, what it does doesn’t really matter, the problem is: how to test this function since it’s supposed to run forever?
I don’t mind to have just unit tests for this function because I already have more integration-like tests for the classes it uses. The first solution I thought was something like this:
this way I could mock
should_continue() in my test and make it return
False to abort the loop when I want. That works but it’s ugly! I don’t like to add dependency injections only for tests.
I asked on #python on irc and marienz gave a neat idea: raise an exception.
I could mock
sequential.process() and raise an exception, this way I know they were called as I expected and also it will also abort the loop!
This test uses py.test and mock. I hope the comments explains enough. The idea is simple: make
process() raise an Exception to abort the loop.
ErrorAfter class is a small helper, it builds a callable object that will raise a specific exception after
n calls. I created a custom exception here to make sure my test fails if any other exception is raised. See the code bellow.
Try to avoid as much as possible to create dependency injections specifically for your tests. In dynamic languages like Python it’s very easy to replace a specific component with a mock object without adding extra complexity to your code just to allow unit testing.
This was the first time I had to test a infinite loop, it’s possible and easy!