Mock/Patch class 方法中的特定 object 方法
Mock/Patch specific object method inside a class method
我知道标题很混乱,但为了清楚起见,我创建了一个我必须转置的示例:
假设我在 class_file.py
中有这段代码
class CarDealership:
def allow_car_out_of_the_dealership(self, car):
logger.info(f"Driving out of the dealership")
drivers_license = car.driver.wallet.get_drivers_license()
if drivers_license:
try:
allow_car_removal(car, drivers_license)
except:
deny_car_removal(car, drivers_license)
我正在尝试测试调用方法 deny_car_removal
的情况。 get_valid_license()
是一种特定于 driver.wallet
的方法,不会以任何方式、形状或形式在 class_file.py
中导入或引用。
问题在于,如果 get_valid_license
在实际情况下 return 没有任何有效内容,则代码将采用完全不同的方式。我正在尝试修补 drivers_license
,以便我最终可以将它带到我需要的位置。
我猜 test_class_file.py
应该是这样的:
class CarDealershipTests(BaseTestCase):
@patch('class_file.CarDealership.deny_car_removal')
def test_deny_car_removal(self):
# something here
self.assertTrue(mock_deny_car_removal.called)
我通过查看其他 Whosebug 答案尝试了一些但没有奏效的事情:
- 在测试设置中,在模拟的
car
中模拟完整的 driver
实例,如下所示:
def setUp(self) -> None:
self._create_car
def _create_car(self):
car = Car()
car.driver = MagicMock()
- 尝试使用
@patch.object(class_file.CarDealership.allow_car_out_of_the_dealership, "car.driver.wallet.get_valid_license")
- 尝试使用
@patch.object(class_file.CarDealership.allow_car_out_of_the_dealership, "drivers_license")
- 尝试使用
@patch("class_file.CarDealership.allow_car_out_of_the_dealership.car.driver.wallet.get_valid_license")
- 尝试使用
@patch("class_file.CarDealership.allow_car_out_of_the_dealership.drivers_license")
假设您有一个包含以下内容的文件,如您所示:
import logging
logger = logging.getLogger(__name__)
class CarRemovalFailure(BaseException):
pass
class CarDealership:
def allow_car_out_of_the_dealership(self, car):
logger.info("Driving out of the dealership")
drivers_license = car.driver.wallet.get_drivers_license()
if drivers_license:
try:
allow_car_removal(car, drivers_license)
except CarRemovalFailure:
deny_car_removal(car, drivers_license)
为了调用 deny_car_removal
,我们需要 allow_car_removal
来抛出一个 Exception
。这可以通过使用 Mock
对象的 side_effect
属性轻松完成。
我没有在这个测试中加入任何 setup/tear-down,而是说明 side_effect
是如何工作的,以及它最终如何调用 deny_car_removal
。
from unittest.mock import MagicMock, patch
from class_file import CarDealership, CarRemovalFailure
@patch("class_file.allow_car_removal")
@patch("class_file.deny_car_removal")
def test_deny_car(mock_deny, mock_allow):
mock_allow.side_effect = CarRemovalFailure("Failed!")
car = MagicMock()
cd = CarDealership()
cd.allow_car_out_of_the_dealership(car)
car.driver.wallet.get_drivers_license.assert_called_once()
mock_deny.assert_called_once()
当运行时输出如下:
============================= test session starts ==============================
platform darwin -- Python 3.9.1, pytest-6.2.2, py-1.10.0, pluggy-0.13.1
rootdir: ****
collected 1 item
tests/test_car.py . [100%]
============================== 1 passed in 0.05s ===============================
在您的示例中,您可能不想修补 deny_car_removal
,因为您正在尝试测试逻辑,但由于我不知道那可能是什么,所以我最后修补了它。这样做的目的是说明实际上函数确实被调用了。
我知道标题很混乱,但为了清楚起见,我创建了一个我必须转置的示例:
假设我在 class_file.py
class CarDealership:
def allow_car_out_of_the_dealership(self, car):
logger.info(f"Driving out of the dealership")
drivers_license = car.driver.wallet.get_drivers_license()
if drivers_license:
try:
allow_car_removal(car, drivers_license)
except:
deny_car_removal(car, drivers_license)
我正在尝试测试调用方法 deny_car_removal
的情况。 get_valid_license()
是一种特定于 driver.wallet
的方法,不会以任何方式、形状或形式在 class_file.py
中导入或引用。
问题在于,如果 get_valid_license
在实际情况下 return 没有任何有效内容,则代码将采用完全不同的方式。我正在尝试修补 drivers_license
,以便我最终可以将它带到我需要的位置。
我猜 test_class_file.py
应该是这样的:
class CarDealershipTests(BaseTestCase):
@patch('class_file.CarDealership.deny_car_removal')
def test_deny_car_removal(self):
# something here
self.assertTrue(mock_deny_car_removal.called)
我通过查看其他 Whosebug 答案尝试了一些但没有奏效的事情:
- 在测试设置中,在模拟的
car
中模拟完整的driver
实例,如下所示:
def setUp(self) -> None:
self._create_car
def _create_car(self):
car = Car()
car.driver = MagicMock()
- 尝试使用
@patch.object(class_file.CarDealership.allow_car_out_of_the_dealership, "car.driver.wallet.get_valid_license")
- 尝试使用
@patch.object(class_file.CarDealership.allow_car_out_of_the_dealership, "drivers_license")
- 尝试使用
@patch("class_file.CarDealership.allow_car_out_of_the_dealership.car.driver.wallet.get_valid_license")
- 尝试使用
@patch("class_file.CarDealership.allow_car_out_of_the_dealership.drivers_license")
假设您有一个包含以下内容的文件,如您所示:
import logging
logger = logging.getLogger(__name__)
class CarRemovalFailure(BaseException):
pass
class CarDealership:
def allow_car_out_of_the_dealership(self, car):
logger.info("Driving out of the dealership")
drivers_license = car.driver.wallet.get_drivers_license()
if drivers_license:
try:
allow_car_removal(car, drivers_license)
except CarRemovalFailure:
deny_car_removal(car, drivers_license)
为了调用 deny_car_removal
,我们需要 allow_car_removal
来抛出一个 Exception
。这可以通过使用 Mock
对象的 side_effect
属性轻松完成。
我没有在这个测试中加入任何 setup/tear-down,而是说明 side_effect
是如何工作的,以及它最终如何调用 deny_car_removal
。
from unittest.mock import MagicMock, patch
from class_file import CarDealership, CarRemovalFailure
@patch("class_file.allow_car_removal")
@patch("class_file.deny_car_removal")
def test_deny_car(mock_deny, mock_allow):
mock_allow.side_effect = CarRemovalFailure("Failed!")
car = MagicMock()
cd = CarDealership()
cd.allow_car_out_of_the_dealership(car)
car.driver.wallet.get_drivers_license.assert_called_once()
mock_deny.assert_called_once()
当运行时输出如下:
============================= test session starts ==============================
platform darwin -- Python 3.9.1, pytest-6.2.2, py-1.10.0, pluggy-0.13.1
rootdir: ****
collected 1 item
tests/test_car.py . [100%]
============================== 1 passed in 0.05s ===============================
在您的示例中,您可能不想修补 deny_car_removal
,因为您正在尝试测试逻辑,但由于我不知道那可能是什么,所以我最后修补了它。这样做的目的是说明实际上函数确实被调用了。