You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mock模拟Django模型DoesNotExist异常时捕获失败问题咨询

Why can't my Django model's mocked DoesNotExist exception be caught specifically?

The Problem

I'm writing unit tests for a Django function, using Mock to simulate a missing object scenario:

from models import MyObject
mock_obj.objects.get.side_effect = mock.Mock(side_effect=MyObject.DoesNotExist)

When my function catches a generic Exception, the test passes:

import models
try:
    obj = models.MyObject.objects.get(id=1)
except Exception:
    return True

But when I switch to catching the specific models.MyObject.DoesNotExist exception, the test fails with this traceback:

Traceback (most recent call last):
File "/home/test/test_my_function.py", line 40, in test_get_job_not_exist
response = my_function.my_function(request_mock, 1)
File "/home/handlers/my_function.py", line 35, in get_job_with_id
obj = MyObject.objects.get(id=id)
File "/local/lib/python2.7/site-packages/mock/mock.py", line 1062, in call
return _mock_self._mock_call(*args, **kwargs)
File "/local/lib/python2.7/site-packages/mock/mock.py", line 1118, in _mock_call
raise effect
DoesNotExist

MyObject is a Django model. Why isn't the specific exception catch working?


What's Going Wrong & How to Fix It

There are two key issues here that are breaking your specific exception handling:

1. You're wrapping the exception in an unnecessary Mock

Your current code sets the side_effect to a Mock instance that throws the exception, instead of directly using the exception class itself.

When you write:

mock_obj.objects.get.side_effect = mock.Mock(side_effect=MyObject.DoesNotExist)

You're creating a nested Mock: when get() runs, it triggers the inner Mock, which then throws the exception. This can break the identity check Django uses for model-specific exceptions (since each model gets its own unique DoesNotExist subclass at runtime).

Fix: Assign the exception class directly to side_effect:

# Correct approach: no extra Mock wrapper
mock_obj.objects.get.side_effect = MyObject.DoesNotExist

Or if you want to include a custom error message:

mock_obj.objects.get.side_effect = MyObject.DoesNotExist("Object with ID 1 not found")

2. You might be mocking the wrong manager instance

In Python, imports are module-specific. If your test file imports MyObject directly from models, but your function uses import models and references models.MyObject.objects, you could be mocking a different manager instance than the one your function is actually using.

Django ties model managers to the model class in the module where they're referenced. To fix this, mock the exact path your function uses to access objects.get.

For example, if your function lives in my_function.py and uses models.MyObject.objects.get, mock my_function.models.MyObject.objects.get instead of your test file's models.MyObject.objects.get:

from unittest.mock import patch
from my_function import my_function

def test_get_job_not_exist():
    # Mock the exact path the function uses to access get()
    with patch('my_function.models.MyObject.objects.get') as mock_get:
        mock_get.side_effect = MyObject.DoesNotExist
        # Run your function
        result = my_function(request_mock, 1)
        assert result is True

Why This Works

Django generates a unique DoesNotExist subclass for every model at runtime. When you mock correctly, you ensure the exception being thrown is exactly the same class instance that your function is trying to catch. Wrapping it in an extra Mock or targeting the wrong import path breaks this identity, causing the exception to slip past your specific catch block.

内容的提问来源于stack exchange,提问作者Pear

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:54:13