如何在单元测试中Mock类方法调用的跨模块sendemail方法?
解决Mock跨模块sendemail方法的路径问题
你的问题核心是Mock路径错误,当前@patch("app.config.parse_config.logger.critical.sendemail")完全不符合实际调用逻辑。要正确Mock,必须遵循Mock被调用代码所在模块中导入的目标对象这一核心原则。
调用链分析
parse_config.py中调用的logger.critical(),其logger是基于CwLogger类的实例CwLogger.critical()方法内部直接调用的sendemail函数,是从app.utils.sendemail导入到app.utils.logging模块中的引用- 你需要Mock的是
app.utils.logging模块内的sendemail引用,而非logger.critical下的子属性(该属性根本不存在)
修正后的测试代码
将patch路径改为app.utils.logging.sendemail,修改后的测试方法如下:
@patch.dict(os.environ, {"AWS_REGION": region, "CW_MODE": mode}) @patch('app.config.parse_config.get_from_ssm') @patch('app.config.parse_config.process_queue') @patch("app.utils.logging.sendemail") # 正确的Mock路径 def test_parse_args_no_mandatory(self, mock_sendmail, mock_process_queue, mock_get_from_ssm): mock_get_from_ssm.side_effect = ["x", "y"] tmp_config = copy.deepcopy(good_min_config) mock_sendmail.return_value = None del tmp_config["username"] mock_process_queue.return_value = tmp_config with pytest.raises(SystemExit) as pytest_wrapped_e: parse_config() self.assertEqual(SystemExit, pytest_wrapped_e.type) self.assertEqual("config option: username not supplied", pytest_wrapped_e.value.code) # 可选:验证sendemail是否被正确触发 mock_sendmail.assert_called_once()
关键原理说明
Python的Mock是通过替换模块命名空间中的对象生效的。CwLogger.critical里调用的sendemail,是app.utils.logging模块中导入的函数引用,必须针对这个引用的路径做Mock——而非从调用者parse_config的角度找路径,也不建议直接Mock原函数的定义路径(虽偶能生效,但针对使用场景的引用Mock更可靠)。
内容的提问来源于stack exchange,提问作者JobyB
相关产品推荐
相关产品推荐

