如何在Python 3.5中使用unittest.mock模拟导入的库方法?

时间:2015-12-22 13:57:08

标签: python unit-testing mocking

是否可以在Python 3.5中使用unittest.mock模拟导入模块的方法?

# file my_function.py
import os
my_function():
    # do something with os, e.g call os.listdir
    return os.listdir(os.getcwd())

# file test_my_function.py
test_my_function():
    os = MagickMock()
    os.listdir = MagickMock(side_effect=["a", "b"])
    self.assertEqual("a", my_function())

我希望os.listdir方法在第一次调用时返回指定的side_effect“a”,但在my_function内部调用未修补的os.listdir。

1 个答案:

答案 0 :(得分:1)

unitetest.mock有两个主要职责:

  • 定义Mock个对象:旨在关注您的剧本并记录对您模拟对象的每次访问的对象
  • 修补引用并恢复原始状态

在您的示例中,您需要两个功能:通过模拟修补生产代码中使用的os.listdir引用,您可以完全控制它将响应。有很多方法可以使用patch,有些details to take care on how use itcavelets to know

在您的情况下,您需要测试my_function()行为,您需要修补os.listdir()os.getcwd()。此外,您需要控制return_value(请查看return_valueside_effect差异的尖端文档。

我重写了你的例子,使其更加完整和清晰:

my_function(nr=0):
    l = os.listdir(os.getcwd())
    l.sort()
    return l[nr]

@patch("os.getcwd")
@patch("os.listdir", return_value=["a","b"])
def test_my_function(mock_ld, mock_g): 
    self.assertEqual("a", my_function(0))
    mock_ld.assert_called_with(mock_g.return_value)
    self.assertEqual("a", my_function())
    self.assertEqual("b", my_function(1))
    with self.assertRaises(IndexError):
        my_function(3)

我使用了装饰器语法,因为我认为它是更干净的方法;此外,为避免引入太多细节,我没有使用自动调整 我认为这是一种非常好的做法。

最后注意:模拟是一个功能强大的工具,但使用它而不是滥用它,补丁只需要修补,而不是其他。