模拟自己 class 的基础 class 时的 StopIteration
StopIteration when mocking base class of own class
在一个相当复杂的测试场景中,我需要模拟我自己的 class 之一的基础 class 并多次实例化后者。当我这样做时,我的测试错误出现 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
class 但我不知道发生了什么。在 MagicMock 的 _execute_mock_call()
方法中,我注意到 self.side_effect
是一个元组迭代器对象,当在第二个测试(test_mock_2
)中调用 next()
时,它会导致 StopIteration
.
如果我不使用 MySession
subclass,即 MyClass 的 init()
方法中的 self.session = OAuth2Session(client=client)
,则两个测试 运行 “OK”。 (但这并不是被测试的真实代码的工作方式......)
有什么想法吗?
你应该模拟你直接使用的 class,因为你的自定义 class 继承 Mock 并接下来开始意外行为。
将路径方法重写为您的自定义 class。
import unittest
from unittest.mock import patch
with patch('my_class.MySession') as MockSession:
from my_class import MyClass
在一个相当复杂的测试场景中,我需要模拟我自己的 class 之一的基础 class 并多次实例化后者。当我这样做时,我的测试错误出现 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
class 但我不知道发生了什么。在 MagicMock 的 _execute_mock_call()
方法中,我注意到 self.side_effect
是一个元组迭代器对象,当在第二个测试(test_mock_2
)中调用 next()
时,它会导致 StopIteration
.
如果我不使用 MySession
subclass,即 MyClass 的 init()
方法中的 self.session = OAuth2Session(client=client)
,则两个测试 运行 “OK”。 (但这并不是被测试的真实代码的工作方式......)
有什么想法吗?
你应该模拟你直接使用的 class,因为你的自定义 class 继承 Mock 并接下来开始意外行为。
将路径方法重写为您的自定义 class。
import unittest
from unittest.mock import patch
with patch('my_class.MySession') as MockSession:
from my_class import MyClass