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

为何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逻辑理解偏差:

  1. 混淆方法调用与属性访问:如果size是实例方法(def size(self): ...),直接访问jar_2.size拿到的是Mock对象本身,而非它的返回值——必须调用jar_2.size()才能获取你设定的return_value。
  2. @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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 06:45:36