导入时调用了模拟函数

5 投票
3 回答
1887 浏览
提问于 2025-04-17 23:42

我有一个模块需要测试,这个模块在导入时会调用一个函数,但出于各种原因我不能直接调用这个函数。所以我在模拟这个函数,但即使是模拟它也会触发导入。

比如,我正在测试的文件是 mod1.py,内容大概是这样的:

import os

def bar():
    return 'foo'

def dont_call():
    os.listdir("C:\\tmp")

dont_call()

而我的测试代码看起来像这样:

import mock

@mock.patch("mod1.dont_call")
def test_mod1(mock_dont_call):
    import mod1
    assert mod1.bar()=='foo'

if __name__=="__main__":
    test_mod1()

问题是 os.listdir 这个函数被调用了。

我不能修改 mod1,那我该怎么办呢?

我使用的是 python2.7。

为了让你更明白,我正在测试一个在导入时会打开数据库连接的模块,我对此并不赞同,但我能理解这样做的原因。不幸的是,我在我的测试机器上无法访问这个数据库。

3 个回答

0

检查你的目录

$tree.
test_shot/
├── mod1.py
├── __pycache__
│   └── mod1.cpython-310.pyc
└── test.py

下面的代码对我来说运行得很好。

mod1.py
import os

def bar():
    return 'foo'

def dont_call():
    os.listdir(".")

def call_this():
    print('called this')

call_this()
dont_call()

test.py

import mock

@mock.patch("mod1.dont_call")
def test_mod1(mock_dont_call):
    import mod1
    assert mod1.bar()=='foo'

if __name__=="__main__":
    test_mod1()

这是输出结果:

$cd test_shot
$python3 test.py
called this
2

如果你想让代码在导入时“不要”被执行,可以把它放在下面的条件里:

在 mod1.py 文件中,做如下操作:

if __name__=="__main__":
    dont_call()

这是因为,默认情况下,当你导入一个 Python 模块时,里面的所有代码都会被执行。通过添加上面的条件,你明确表示只有在这个文件作为脚本运行时,才会调用 dont_call(),而在其他模块导入它时则不会调用。

0

我找到的解决办法是模拟一下dont_call这个函数所调用的内容,这样我就得到了类似下面的东西:

import mock

@mock.patch("os.listdir")
def test_mod1(mock_dont_call):
    import mod1
    assert mod1.bar()=='foo'

if __name__=="__main__":
    test_mod1()

撰写回答