Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock Django Model Queries

I would like to mock the following CanonPerson model

def compute(self, is_send_emails, test_email_address):
        cpses = CanonPerson.objects.filter(persons__vpd=6,
                                           persons__country="United States",
                                           persons__role__icontains=';IX;').prefetch_related("persons").using("global")

        for cp in cpses:
           ...

I am quite lost how to mock CanonPerson.objects.filter to return me an interable collection, so that I can continue.

This is what I have done so far:

def test_X_count(self):
    with mock.patch('apps.dbank.models.CanonPerson.objects.filter') as canon_patch:
        mock_cp = mock.MagicMock(spec=CanonPerson)
        mock_person = mock.MagicMock(spec=Person)
        mock_person.vpd = 6
        mock_cp.country = "United States"
        mock_cp.role = ";IX;"
        mock_cp.persons.add(mock_person)
        canon_patch.objects.filter.return_value = [mock_cp] // ???
        oi = OptinInvites()
        oi.compute(False, None)
        oi.get_most_recent_email.assert_called_once_with(1)

In the compute function I can see cpses is a MagicMock type. However it is not iterable and the for loop there after, just jumps over it. I thought by setting the return value to [mock_cp] I would have created an iterable list?

like image 324
Houman Avatar asked Oct 24 '14 11:10

Houman


1 Answers

The line where you assign a return value to canon_patch is slightly wrong. Where you have:

canon_patch.objects.filter.return_value = [mock_cp]

It should be:

canon_patch.return_value = [mock_cp]

canon_patch is already the mock of 'objects.filter'.

Your original line would return [mock_cp] if you called CanonPerson.objects.filter.objects.filter().

If you actually want to patch out the CanonPerson model then your patch line would look something like:

with mock.patch('apps.dbank.models.CanonPerson') as canon_patch:

You might also find that you need to mock it in the location that it is being used, rather than the location you are importing it from. So assuming you are using CanonPerson in a module called my_module your patch code in the test might look like this:

with mock.patch('my_module.CanonPerson') as canon_patch:
like image 95
aychedee Avatar answered Nov 15 '22 07:11

aychedee