为何Mock的Jar.size方法未返回设置的return_value值?
Mock类方法/属性时返回值不生效的原因及解决办法
问题重现
你定义了Jar类,其中size()方法返回罐内物品数量,deposit()方法会调用size()做检查。测试时尝试用patch.object Mock size()的返回值,但运行时出现:
TypeError: '>' not supported between instances of 'MagicMock' and 'int'- 排查测试中直接断言
jar_2.size == 10,得到AssertionError: <MagicMock name='size' id='xxx'> != 10
测试代码:
from jar import Jar from unittest.mock import patch import unittest class JarTestCase(unittest.TestCase): @patch.object(Jar, 'size') def test_deposit(self, mock_size): jar_2 = Jar() mock_size.return_value = 10 self.assertRaises(ValueError, jar_2.deposit, 20) self.assertEqual(jar_2.size, 10) class JarTestCase(unittest.TestCase): @patch.object(Jar, 'size') def test_size (self, mock_size): jar_2 = Jar() mock_size.return_value = 10 self.assertEqual(jar_2.size, 10)
核心原因
问题出在Mock对象的访问方式错误,以及对实例方法/属性的Mock逻辑理解偏差:
- 混淆方法调用与属性访问:如果
size是实例方法(def size(self): ...),直接访问jar_2.size拿到的是Mock对象本身,而非它的返回值——必须调用jar_2.size()才能获取你设定的return_value。 - @property的Mock方式错误:如果
size是用@property装饰的属性,直接patch类上的size属性无法正确覆盖实例的属性访问逻辑,因为@property是描述符,需要针对其getter进行Mock。
分场景解决方案
场景1:size是实例方法
假设你的Jar类定义如下:
class Jar: def __init__(self): self._count = 0 self.capacity = 15 # 假设默认容量15 def size(self): return self._count def deposit(self, n): if self.size() + n > self.capacity: raise ValueError("Exceeds capacity") self._count += n
修正测试代码,确保调用size()方法而非直接访问属性:
from jar import Jar from unittest.mock import patch import unittest class JarTestCase(unittest.TestCase): @patch.object(Jar, 'size') def test_deposit(self, mock_size): jar_2 = Jar() mock_size.return_value = 10 # 验证存入20会触发ValueError(10+20>15) self.assertRaises(ValueError, jar_2.deposit, 20) # 调用size()获取返回值 self.assertEqual(jar_2.size(), 10) @patch.object(Jar, 'size') def test_size(self, mock_size): jar_2 = Jar() mock_size.return_value = 10 self.assertEqual(jar_2.size(), 10)
场景2:size是@property属性
假设你的Jar类定义如下:
class Jar: def __init__(self): self._count = 0 self.capacity = 15 @property def size(self): return self._count def deposit(self, n): if self.size + n > self.capacity: raise ValueError("Exceeds capacity") self._count += n
可以通过两种方式修正测试:
方式1:直接Mock实例的size属性
class JarTestCase(unittest.TestCase): def test_deposit(self): jar_2 = Jar() # 针对单个实例Mock size属性 with patch.object(jar_2, 'size', return_value=10): self.assertRaises(ValueError, jar_2.deposit, 20) self.assertEqual(jar_2.size, 10)
方式2:Mock类的property getter
class JarTestCase(unittest.TestCase): @patch.object(Jar.size.fget, 'return_value', 10) def test_deposit(self): jar_2 = Jar() self.assertRaises(ValueError, jar_2.deposit, 20) self.assertEqual(jar_2.size, 10)
总结
- 若
size是方法:必须调用size()才能获取Mock返回值,直接访问size得到的是Mock对象本身。 - 若
size是@property:优先选择Mock实例属性(更直观),或针对property的getter方法进行Mock。
内容的提问来源于stack exchange,提问作者Lucas Fonseca Alexandre de Oli
相关产品推荐
相关产品推荐

