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

如何在类级别mock select.select?单元测试遇TypeError问题

解决类级别Mock select.select时的TypeError问题

问题原因

你遇到的TypeError: fileno() returned a non-integer本质是:类属性里定义的select_mock = patch('select.select')只是创建了一个patch对象,但没有真正激活它。此时代码里调用的select.select还是系统原生函数,它会尝试检查传入socket的fileno()方法返回值,而你的socket_mock是普通Mock对象,没有实现fileno(),所以触发报错。

而测试方法里用@patch装饰器时,装饰器会自动在测试前后启动/停止patch,把原生select.select替换成Mock对象,此时原生函数不会执行,自然不会去检查socket的fileno()。

解决方案

方案1:在类级别手动管理patch的启动与停止

修改setUpClass和tearDownClass,手动启动patch并保存补丁对象,测试完成后停止:

class ClientTestsBase(unittest.TestCase):
    socket_mock = mock.Mock()
    select_mock = None  # 先初始化,后面赋值启动后的patch对象
    client = None

    @classmethod
    def setUpClass(cls):
        # 创建并启动patch,替换原生select.select
        cls.select_mock = mock.patch('select.select').start()
        cls.select_mock.return_value = [cls.socket_mock], [], []
        
        cls.client = Client(1, cls.socket_mock, '0.0.0.0:0')
        os.environ["DEFAULT_TIMEOUT_SECONDS"] = '300'

    @classmethod
    def tearDownClass(cls):
        # 停止patch,恢复原生select.select
        mock.patch.stopall()

测试方法保持不变即可:

def test_get(self):
    self.socket_mock.recv.return_value.decode.return_value = 'y'
    response = self.client.get()
    self.assertEqual(response, 'y') 

方案2:用@patch装饰整个测试类

直接给测试类加上@patch装饰器,这样所有测试方法都会自动使用这个mock:

@mock.patch('select.select')
class ClientTestsBase(unittest.TestCase):
    socket_mock = mock.Mock()
    client = None

    @classmethod
    def setUpClass(cls, select_mock):
        select_mock.return_value = [cls.socket_mock], [], []
        
        cls.client = Client(1, cls.socket_mock, '0.0.0.0:0')
        os.environ["DEFAULT_TIMEOUT_SECONDS"] = '300'

    def test_get(self, select_mock):
        self.socket_mock.recv.return_value.decode.return_value = 'y'
        response = self.client.get()
        self.assertEqual(response, 'y') 

注意:用类装饰器时,setUpClass和每个测试方法都需要接收select_mock参数,装饰器会自动注入这个mock对象。

为什么实例setUp里的尝试无效?

你之前在setUp里用@patch装饰的方式,虽然会启动patch,但Client实例是在setUpClass中创建的,此时patch还未启动,Client初始化时可能已经调用了select.select,导致原生函数被触发,依然会报错。所以必须确保在创建Client实例之前就启动patch。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 02:20:16