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

单元测试中如何模拟伪造配置路径?

单元测试中动态替换导入的静态路径变量

问题场景

原业务代码通过from custom_paths import CONFIG_PATH导入静态路径变量,用于加载配置文件:

from custom_paths import CONFIG_PATH
import os
import yaml

class SomethingCool:
    def __init__(self, filepath: str) -> None:
        with open(os.path.join(CONFIG_PATH, filepath)) as fd:
            self.config = yaml.safe_load(fd)
        # 其他业务逻辑

需求:单元测试时需将CONFIG_PATH从默认的foobuzz/configs替换为tests/foobuzz/configs(由TESTS_PATH定义),但多次尝试后路径仍未改变。

无效的尝试

尝试1:monkeypatch 修改原模块变量

import os
import custom_paths
from my_module import SomethingCool

TESTS_PATH = "tests/foobuzz"

def return_fake_path():
    return os.path.join(TESTS_PATH, "configs")

def test_config_simple(monkeypatch):
    monkeypatch.setattr(custom_paths, "CONFIG_PATH", return_fake_path)
    coolstuff = SomethingCool("test.yml")
    # 断言逻辑

尝试2:mock.patch 修改原模块变量

import os
from unittest import mock
from my_module import SomethingCool

TESTS_PATH = "tests/foobuzz"
FAKE_CONFIG_PATH = os.path.join(TESTS_PATH, "configs")

@mock.patch("custom_paths.CONFIG_PATH", FAKE_CONFIG_PATH)
def test_config_simple():
    coolstuff = SomethingCool("test.yml")
    # 断言逻辑

核心原因

from custom_paths import CONFIG_PATH会将custom_paths模块中的CONFIG_PATH值复制一份到当前业务模块(比如my_module.py)的命名空间。后续修改custom_paths模块里的CONFIG_PATH,不会影响已经导入到业务模块的变量引用。

正确解决方案

需要修改的是业务模块中已经导入的CONFIG_PATH,而非原custom_paths模块中的变量。

方案1:使用 pytest monkeypatch

import os
from my_module import SomethingCool
import pytest

TESTS_PATH = "tests/foobuzz"
FAKE_CONFIG_PATH = os.path.join(TESTS_PATH, "configs")

def test_config_simple(monkeypatch):
    # 替换业务模块my_module中的CONFIG_PATH
    import my_module
    monkeypatch.setattr(my_module, "CONFIG_PATH", FAKE_CONFIG_PATH)
    
    coolstuff = SomethingCool("test.yml")
    assert coolstuff.config == expected_config

方案2:使用 unittest.mock.patch

import os
from unittest import mock
from my_module import SomethingCool

TESTS_PATH = "tests/foobuzz"
FAKE_CONFIG_PATH = os.path.join(TESTS_PATH, "configs")

# 目标是业务模块my_module中的CONFIG_PATH,而非原custom_paths模块
@mock.patch("my_module.CONFIG_PATH", FAKE_CONFIG_PATH)
def test_config_simple():
    coolstuff = SomethingCool("test.yml")
    assert coolstuff.config == expected_config

验证方法

可在业务代码的__init__方法中临时添加打印语句,确认路径是否替换成功:

class SomethingCool:
    def __init__(self, filepath: str) -> None:
        print(f"当前CONFIG_PATH: {CONFIG_PATH}")  # 测试时查看是否为测试路径
        with open(os.path.join(CONFIG_PATH, filepath)) as fd:
            self.config = yaml.safe_load(fd)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 15:47:19