Pytest part I
2017-03-27

This post (and maybe eventually series) is meant to document my journey with the Pytest library (combined with native Python testing libs). Of my, admittedly few, posts thus far, this one is really aimed at future me.

When I was in college, testing wasn't a subject that came up. At my first job out of college, it was entirely manual. At my next job...there were tests, but it was part of a 15-20 minute build process, and was therefore not part of the basic dev cycle. Or at least, that was the state when I started there.

A few years later, the company started shifting from Java to Ruby (entirely via Rails). With that shift came a healthy questioning of assumptions, which among other things led to a test first approach to new projects. Given the Rails ecosystem at that time, our testing framework of choice was Factory Bot. Since then, that approach to projects has stuck with me. Even if I tend to agree with (prag) Dave Thomas with respect to questioning the need for all the tests, I still usually write them, especially with team projects.

That was a long preamble to my recent experience with Pytest. At my latest gig, Python is the language of choice for both the main server side code as well as background tasks, scripting, and basically anything not client side. The project was using Nose, but the team had no issue with my transitioning to Pytest given the relative level of maintenance.

Due to my testing roots, and my continued preference for expressive test method names, I much prefer should* names over test*. The following config (pytest.ini) will set that up.

  
1 [pytest]
2 python_functions=should_*

Next, I wanted my mocks back. I held off for some time, because Pytests fixture's are very nice (and well documented). Python's built in mocks are plenty sufficient for my current needs, but the documentation examples are somewhat lacking (they are there, but it kinda shows many ways to achieve similar results without even a gentle push in a decent direction). After a bit of research this is roughly what I settled on for my first use.

  
1 def should_work():
2 with mock.patch('module_under_test.ThingToBeMocked') as Mock:
3 instance = Mock.return_value
4 instance.instance_method.return_value = 'some value'
5 
6 actual = module_under_test.ThingToBeMocked.instance_method()
7 assert actual == expected

I'm not a huge fan of my example. If I end up writing a part two, it will be a small but more real project, likely Github hosted and highlighted here, so that the examples can be a bit closer to what someone might actually write.