A few talks were around testing things.
Let's pretend we're accountants. Lines of code are liabilities, not assets. And with a liability, comes interests, also known as maintenance.
Tests are a way to lower the interest rate over your technical debt. But unlike a common thinking, technical debt is not only about bad code. It's about all code. Any code has a maintenance cost, worse it is and higher the cost will be, but still, even the best code has a running cost.
Type of tests
Nothing new here
- Unit tests: take the smallest part possible in a system and assert it behaves the way you want. Always remove all the dependencies you can, you do not want the database, the filesystem, some service or anything to come into play here.
- End-to-end / Integration tests: take two services and test how they interract. For example, a site and a database.
- System tests: take all your services and test the critical paths so you can be safe when you release a new version of any of your services.
Docker containers as fixtures
Why not using py.test fixtures to create clean and reproducible instances of the test dependencies as docker containers? Fixtures in py.test are mostly a way to group a setup and a teardown that will be used in a single test or in a group of tests, and basically, what you want to run integration tests with docker containers is some way to bring up a clean-state container before the test is run, use it as a dependency in the test, then kill it with no second thought.
Oh, wait? Isn't that the exact same as setup/teardown?
Code examples: https://github.com/keeppythonweird/pytest-dockerpy
A great presentation was about the unittest.mock package (or mock package if you're still using python2).
- Mock / MagicMock classes can be used to replace anything, and will record all calls so you can assert what was called. The later also replaces the double underscore methods (so you can operate on it as iterator, add mocks, substract mocks, etc...) and you can restrict the possible calls using spec=something to mimic something's methods.
- patch() is both a decorator and a context processor that replace something by a MagicMock in a given context, then restore the old value. Be carefull about imports, if you from os import path in a foobar package, then you want to patch('foobar.path', ...), if you import os.path in the very same package, then you'll need to patch('os.path', ...).
I took part in the py.test sprints. I was amazed to see how the core team thought of it as a one-sided thing, being so grateful for the (small) contribution. My contribution was so small that I even joked about it being more like a slow walk than a sprint, but looks like their perception was different.
But it is not one sided. Sprints are amazing, and if you're a tech guy, unrelated to how experienced you are, you should definitely try it one day.
The fact is that by sprinting on a project, you get different things:
- You get to know a bit the core contributors.
- You get to understand how they organized the development of a rather big, multi-contributor, stable project.
- You dive in the internals of a project you're using, getting a better understanding on how things work.
- And afterall, if you get value from an open-source project, you should consider giving back a little something, from time to time.