Kev*_*her 5 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())
Run Code Online (Sandbox Code Playgroud)
我期望 os.listdir 方法在第一次调用时返回指定的 side_effect “a”,但在 my_function 内部调用未修补的 os.listdir 。
unittest.mock有两个主要职责:
Mock对象:旨在遵循您的剧本并记录对模拟对象的每次访问的对象在您的示例中,您需要这两种功能:os.listdir通过模拟修补生产代码中使用的引用,您可以完全控制它将如何响应。使用方法有很多,需要注意patch一些细节以及使用注意事项。
在您的情况下,您需要测试my_function()行为并且需要修补os.listdir()和os.getcwd()。此外,您需要的是控制return_value(查看指定的文档以了解return_value差异side_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)
Run Code Online (Sandbox Code Playgroud)
我使用装饰器语法是因为我认为它是更简洁的方法;此外,为了避免引入太多细节,我没有使用我认为是最佳实践的自动指定。
最后一点:模拟是一个强大的工具,但要使用它而不是滥用它,修补只是你需要修补的事情,仅此而已。