为何使用Mock对象的Python/Django单元测试无法正常运行?
嘿,我看到你在Django模型的Mock测试上踩坑了,咱们来捋清楚问题出在哪:
核心问题:混淆了Mock类和Mock实例
你现在的测试失败,根源是错误地修改了Mock类对象的方法,而非类实例的方法:
- 当你用
@mock.patch('run.models.Book', autospec=True)装饰测试方法时,参数mock_book是Book类的Mock替身,不是具体的实例。 - 调用
Book()等价于调用mock_book(),会返回mock_book.return_value——这才是模拟出来的Book实例对象。 - 你之前修改的
mock_book.retrieve_isbn是类级别的方法,但实际调用的是实例的retrieve_isbn,所以你的Mock设置根本没作用到目标对象上,自然还是返回原方法的abc123。
修正后的测试代码
# tests.py import unittest from unittest import mock from run.models import Book class TestModel(unittest.TestCase): @mock.patch('run.models.Book', autospec=True) def test_book_isbn(self, mock_book): # 配置Mock实例的retrieve_isbn返回值 mock_book_instance = mock_book.return_value mock_book_instance.retrieve_isbn.return_value = 'foo123' # 调用实例方法(此时Book()会返回我们配置好的Mock实例) isbn = Book().retrieve_isbn() # 断言结果 self.assertEqual(isbn, 'foo123')
额外小提示
- 你的测试用例里并没有用到
Author的逻辑,完全可以去掉@mock.patch('run.models.Author'),减少不必要的Mock复杂度。 - 用
autospec=True是个好习惯,它会强制Mock遵循原类的结构,避免你设置不存在的属性/方法,但要注意:类属性和实例属性要区分开,比如你之前设置的mock_book.title是无效的,因为title是实例属性,不是类属性。 - 还有一种等价的写法,直接给实例方法赋值MagicMock:
mock_book.return_value.retrieve_isbn = mock.MagicMock(return_value='foo123')
内容的提问来源于stack exchange,提问作者Jim
相关产品推荐
相关产品推荐

