Jack Evans
Jack Evans

Reputation: 1717

Django Patch Side effect IntegrityError not being raised

I have the following view, which excepts POST requests, and serializes an objects data (a Draftschedule) to create a new copy (a FrozenSchedule):

from reports.tasks import create_frozen_schedule

def freeze_schedule(request, pk):
    """Valid post request will freeze a Draft Schedule serializing its data"""
    client = get_object_or_404(Client, draftschedule=pk)
    try:
        # Serialize data into a FrozenSchedule object
        frozenschedule = create_frozen_schedule(pk, request.user.id)
    except IntegrityError:
        # Warn user if action failed
        messages.warning(request, "A Schedule of this Type already exists")
        return redirect(client.draftschedule)
    else:
        # If Schedule is Frozen successfully
        messages.success(request, "Schedule Frozen")
        return redirect(frozenschedule)

I'm trying to write a test to assert certain things happen after an IntegrityError is raised. I'm struggling to understand why it's failing, it's not immediately obvious to me where I'm going wrong since I'm fairly inexperienced with mocking / patching.

I've tried to mock the create_frozen_schedule function to raise an IntegrityError when called:

def setUp(self):
    self.url = reverse(
        'reports:draftschedule-freeze',
        args=[self._client.draftschedule.pk]
    )
    super(TestFreezeSchedule, self).setUp()


@patch('reports.tasks.create_frozen_schedule')
def test_freeze_schedule_with_conflict(self, mock_freeze):
    mock_freeze.side_effect = IntegrityError
    with self.assertRaises(IntegrityError):
        self.client.post(self.url)

   # More unit tests following same premise...

But I end up with the following error:

.......................................................................................F............
======================================================================
FAIL: test_freeze_schedule_with_conflict (reports.tests.test_views.TestFreezeSchedule)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/python3.4/unittest/mock.py", line 1136, in patched
    return func(*args, **keywargs)
  File "/home/jwe/piesup2/reports/tests/test_views.py", line 495, in test_freeze_schedule_with_conflict
    self.client.post(self.url)
AssertionError: IntegrityError not raised

----------------------------------------------------------------------

Points to note:

Any ideas why the side effect isn't being raised?

Upvotes: 0

Views: 1098

Answers (2)

Curtis Pew
Curtis Pew

Reputation: 117

If you want to really test that your function throws the exception, you need to test the function directly rather than through the POST. Something like:

from django.test import RequestFactory

@patch('reports.tasks.create_frozen_schedule')
def test_freeze_schedule_with_conflict(self, mock_freeze):
    mock_freeze.side_effect = IntegrityError
    myrequest = RequestFactory().post(*some_url*)
    # you may need to add, e.g., items to myrequest.POST
    with self.assertRaises(IntegrityError):@patch('reports.tasks.create_frozen_schedule')
        freeze_schedule(myrequest, pk)

Upvotes: 0

Daniel Roseman
Daniel Roseman

Reputation: 599778

Your view catches IntegrityError and returns a redirect. The client post, which is what your test calls, doesn't raise an error at all.

Rather, you should be testing that the actions in the except block happen: is the warning set, and does the post redirect to the draft schedule instead of the frozen one.

Upvotes: 1

Related Questions