When it comes to mocking in Django, I reccomend the mock library. Another advantage, besides faster tests, of using mocking instead of Django's default testing behavior is that you don't need django to setup the database to run your tests, and you can subclass unittest's TestCase instead of django TestCase (which saves you the database cleanup between tests). With the examples provided here I can run these with manage.py test django_testing or with python -m unittest discover -s django_testing. (using Python2.7)
Let's jump right into some code examples.
Let's walk though the test line by line.
First, create a mock user.
user = mock.Mock()
Second , create a mock manager.
manager = mock.Mock(spec=models.SampleManager)
Next, call the method that you want to have do something. You'll notice a bit of trickery here, I'm using the actual SampleManager class and passing my manager mock object in as the self argument. This allows us to capture what our implementation code does with our manager inside the get_by_user method.
models.SampleManager.get_by_user(manager, user)
Finally, assert that your desired result occured. Here, we are asserting that the filter method of our manager mock object was called with the keyword user argument with the value of our user mock.
manager.filter.assert_called_with(user=user)
Let's take a look at a different way to write that same test.
Here, I used the mock library's patch decorator to mock the filter method on the SampleManager class instead of using the 'mock as self' trickery. Let's look at one more way to write this test.
In this example, I'm using the patch decorator a little bit differently. By omitting the second argument, the patch decorator will pass the mock into your test method which will then allow you to do assertions directly against it.
Now, say we want to check for specific return values, consider this test.
Our implementation code would look like this.
That is really all there is to getting started with mocking django. There are a few more advanced things that I will save for a follow up post, so stay tuned for that. I hope this has been helpful, thanks for reading.
Hello... Thank you for your post. I came across it while google for "Python Django Mock". I have used techniques like you describe here in the past with good success. But, I'm having a lot of problems right now mocking out the "save" of a model. I have documented the issue on http://stackoverflow.com/questions/10545049/mocking-django-model-and-save - how do you handle this? What am I doing wrong?
ReplyDeletehi, what do you think about replacing the "from djang_testing.models import ..." with "from .models import ..."?
ReplyDelete