I recently talked at the hsvpy (Huntsville Python) meetup in Huntsville, AL about unit testing and the mock library. You can view my slides on Google Drive or (probably in the near future) on hsvpy’s GitHub page. Huntsville Python is a meetup that talks about different Python libraries and concepts.
I plan on expanding what I talked about in that meetup over the next few weeks of blogs posts. Let’s look at the overview of what I covered Nov. 7th at the meetup and what I’ll cover in the near future.
Unit Testing in Python
I used the nose2 test runner as well as Python’s built-in unittest library to write a unit test for a very trivial Python function that added two numbers. I demonstrated how calling that function with the numbers 2 and 3 resulted in 5, and comparing that result with the integer 5 in a “assertEqual” function call resulted in a passing test.
I also demonstrated that adding 2 and 3 and comparing it to 7 resulted in a failing test. I showed how nose2 displays a failing test, and how using good test case names can quickly help a developer know what went wrong (rather than having to dig into the test code).
The mock library
The mock library is an amazing library that allows you to basically replace an API with any behavior you want. This has so many use cases, but here’s a few:
- Testing something that gets data over the network, but don’t want your unit tests to fail if that server isn’t up or your network connection is down. The real part you want tested is your handling of that data, not the getting of it across a network (at least for your unit tests).
- File access: do you really want your unit tests to fail if a file doesn’t exist? No – more than likely you want to test your processing of the data once that file is open.
- Assuming your third-party API does what it is supposed to do, just test your interaction with that API rather than the code underneath it.
The key assumption here is that in unit testing, you aren’t testing system-level behavior. You test these interactions between the network/OS/third-party APIs during a higher-level test than unit testing.
Now that you have a unit test suite, you can have it run automatically every time a commit is made. If the tests fail, you can get an email. All of this is done automatically! Your tests get run against your code and the status of that run can be sent to you through email, regardless of who committed that code.
This is HUGE for both accountability of the team and keeping up with the status of your code base. I covered Jenkins as a use case for doing this… but only the high-level steps.
When you have a build server for continuous integration, you will have different environments on your local development machine versus what the build server has. Docker is a good tool that can ensure consistency in your build or test environments.
One Docker image can be used on every system doing the building or testing. You won’t have to worry about “It works on my machine!” syndrome anymore!
I plan to elaborate on all these concepts in future posts.
- Unit testing: more examples
- Mock: more examples and more description of its capabilities
- Continuous integration: perhaps an entire setup example of a Python project and a Jenkins server
- Docker: a common docker-compose file example that can be used to run unit tests and perhaps Python package installation testing
One thing I was really happy about during this meetup was the amount of questions I got at the end. People were paying attention and have an interest in using this information to make their testing infrastructure better. This is fantastic!
Stay tuned in the next few weeks, where I will elaborate more on each of these concepts.
If you have specific questions or comments, please let me know in comments section and I’ll try to address them in future posts.