Python Test Doubles

Resources

Video Script

To use test doubles in Python, we’re going to rely on the built-in unittest.mock library. This is by far the easiest way to work with fake objects and method stubs in Python, and we don’t have to install anything else to use it. So, all we have to do is import a few parts of that library into our code. In most cases, we’re going to use the patch annotation, so that’s what we’ll import initially.

To create a fake object using patch, we’ll add the @patch annotation above the unit test method that will use the fake object. In the @patch annotation, we include the full path of the object we are creating as a string, as well as a spec attribute that points to the name of the class we would like it to mimic. So, in this example, we are creating fake versions of the people.Teacher and people.Person classes, using those class names as the spec we’d like to follow. Then, inside of our method definition, we include those objects as parameters. Notice that the @patch annotations are applied inside out. So, the first one for Teacher is the last method parameter, and they work inward from there. This also means that any parameterized unit tests will have the @pytest.mark annotations above the @patch annotations. Finally, inside of our unit test method, we can use those objects just like we would real instances of that class. They’ll satisfy any type checking we do, and will work just fine as lon as we don’t call any methods on that object.

However, if we want to call those methods, we’ll have to include method stubs in our code. In Python, there are several ways to do this, but the easiest is to just replace the method’s return_value attribute with our desired output. Any fake object in Python will already include default implementations of any method, but they will just return nothing. So, we can just update that value to return "Teacher Person", and then in our unit test we can verify that we receive the correct output.

Creating a stub for a property is similar. Instead of changing a method’s return value, we attach a PropertyMock to the type of the fake object. Each fake object created by Python will be given its own type, which we can modify to achieve certain outcomes. So, we simply update the name attribute of the type of our fake_teacher object to a PropertyMock that returns our desired value. Now, in our code, anything that accesses the name property will receive that value. Pretty handy!

Finally, what if we want to create a fake version of a static class? This is a bit more difficult, but thankfully it can be done. Here, we are using the patch.object method to create a method stub for a static method in the TeacherRules class. The only catch is that we must do this in a with statement, which makes sure that the fake static method doesn’t stick around after the unit test. When those static methods are called anywhere within that with statement, it will use our stubbed versions, allowing us to control what the rest of the application sees.

As we can see, using unittest.mock to create fake objects and method stubs in Python is quite simple. However, this is just scratching the surface of what that library can really do. So, feel free to refer to the documentation for additional information and ideas of ways you can use unittest.mock in your unit tests.