【问题标题】:StopIteration when mocking base class of own class模拟自己类的基类时的StopIteration
【发布时间】:2022-01-22 20:36:56
【问题描述】:

在一个相当复杂的测试场景中,我需要模拟我自己的一个类的基类并多次实例化后者。当我这样做时,我的测试错误出现StopIteration 异常。在这方面,我的情况归结为:

正在测试的代码 (my_class.py):

from oauthlib.oauth2 import BackendApplicationClient
from requests_oauthlib import OAuth2Session

class MySession(OAuth2Session):
    pass

class MyClass:
    def init(self, x):
        self.x = x
        client = BackendApplicationClient(client_id=x)
        self.session = MySession(client=client)

测试代码(test_mock.py):

import unittest
from unittest.mock import patch

with patch('requests_oauthlib.OAuth2Session') as MockSession:
    from my_class import MyClass

cls = MyClass()

class MockTest(unittest.TestCase):

    def test_mock_1(self):
        cls.init(1)
        self.assertIsNotNone(cls.session)

    def test_mock_2(self):
        cls.init(2)
        self.assertIsNotNone(cls.session)

测试结果:

$ python -m unittest test_mock
.E
======================================================================
ERROR: test_mock_2 (test_mock.MockTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "...\test_mock.py", line 16, in test_mock_2
    cls.init(2)
  File "...\my_class.py", line 11, in init
    self.session = MySession(client=client)
  File "C:\Python39\lib\unittest\mock.py", line 1093, in __call__
    return self._mock_call(*args, **kwargs)
  File "C:\Python39\lib\unittest\mock.py", line 1097, in _mock_call
    return self._execute_mock_call(*args, **kwargs)
  File "C:\Python39\lib\unittest\mock.py", line 1154, in _execute_mock_call
    result = next(effect)
StopIteration

----------------------------------------------------------------------
Ran 2 tests in 0.003s

FAILED (errors=1)

我已经调试到unittest.mock.MagicMock 类,但我不知道发生了什么。在 MagicMock 的 _execute_mock_call() 方法中,我注意到 self.side_effect 是一个元组迭代器对象,当在第二个测试 (test_mock_2) 中调用 next() 时,它会导致 StopIteration

如果我不使用 MySession 子类,即 MyClass' init() 方法中的 self.session = OAuth2Session(client=client),两个测试都运行“OK”。 (但这并不是真正的被测代码的工作方式......)

有什么想法吗?

【问题讨论】:

    标签: python python-unittest python-unittest.mock magicmock stopiteration


    【解决方案1】:

    您应该模拟您直接使用的类,因为您的自定义类继承了 Mock 并且接下来会启动意外行为。

    将路径方法重写为您的自定义类。

    import unittest
    from unittest.mock import patch
    
    with patch('my_class.MySession') as MockSession:
        from my_class import MyClass
    

    【讨论】:

    • 好吧,也许我过分简化了我的测试场景:事实上,MyClassinit() 方法有两个分支,一个使用MySession,另一个使用基类OAuth2Session。所以我需要模拟两者,我希望我能和基类一起模拟。但是您的回答已经为我指明了正确的方向:在 my_class 导入周围嵌套两个 with patch() 语句。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-25
    • 1970-01-01
    • 1970-01-01
    • 2018-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多