我有以下要测试的python代码:
def find_or_make_logfolder(self):
if not path.isdir(self.logfolder):
try:
makedirs(self.logfolder)
except OSError:
if not path.isdir(self.logfolder):
raise
我想在我的单元测试中执行以下操作。
def test_find_or_make_logfolder_pre_existing(self):
with self.assertRaises(OSError):
makedirs(self.logfolder)
find_or_make_logfolder()
但是,if not path.isdir(self.logfolder):
正在检查目录是否已经存在,以致except OSError
仅在某个边缘情况下抛出,在这种情况下,程序或人员成功地使目录在几毫秒之后生成if
之前和try
之前。
我该如何测试,或者我真的需要测试吗?
当覆盖率100%时,我倾向于喜欢它。
答案 0 :(得分:2)
你可以采用更多的Pythonic路线来实现这一目标。在Python中,哲学是
要求宽恕比要求许可更好。
请参阅EAFP here
考虑到这一点,您的代码可以写成如下:
def find_or_make_logfolder(self):
try:
makedirs(self.logfolder)
except OSError:
#self.logfolder was already a directory, continue on.
pass
现在要覆盖100%的代码,您只需要创建一个目录已经存在的测试用例。
答案 1 :(得分:2)
mock
库是实现100%覆盖率的必备工具。
模拟make_dirs()
函数并在其上设置side_effect
:
side_effect允许你执行副作用,包括提高 调用mock时的异常
from mock import patch # or from unittest import mock for python-3.x
@patch('my_module.makedirs')
def test_find_or_make_logfolder_pre_existing(self, makedirs_mock):
makedirs_mock.side_effect = OSError('Some error was thrown')
with self.assertRaises(OSError):
makedirs(self.logfolder)
答案 2 :(得分:0)
还有很多其他情况会引发OSError,例如:文件系统已满,权限不足,文件已存在等。
在这种情况下,权限很容易被利用 - 只需安排将self.logfolder
设置为您的进程没有写入权限的不存在的目录,例如:在* nix中,假设您在根目录中没有写权限:
>>> import os
>>> os.makedirs('/somedir')
OSError: [Errno 13] Permission denied: '/somedir'
另外,请考虑Martin Konecny建议的重构。
答案 3 :(得分:0)
我迟到了,但我想分享我的解决方案(基于this answer),还包括我的mock
ed单元测试。
我创建了一个函数来创建一个路径,如果它不存在,比如mkdir -p
(并称之为mkdir_p
以便于我记住它。)
<强> my_module.py 强>
import os
import errno
def mkdir_p(path):
try:
print("Creating directory at '{}'".format(path))
os.makedirs(path)
except OSError as e:
if e.errno == errno.EEXIST and os.path.isdir(path):
print("Directory already exists at '{}'".format(path))
else:
raise
如果os.makedirs
无法创建目录,我们会检查OSError
错误号。如果它是errno.EEXIST
(== 17),并且我们看到路径存在,我们不需要做任何事情(虽然打印一些东西可能会有所帮助)。如果错误号是其他的,例如errno.EPERM
(== 13),然后我们引发异常,因为该目录不可用。
我正在通过模拟os
并在测试函数中为OSError
指定错误编号来测试它。 (这使用文件 tests / context.py ,允许从父目录轻松导入,如Kenneth Reitz所示。虽然与问题没有直接关系,但我在此处将其包括在内为了完整起见。)
<强>测试/ context.py 强>
import sys
import os
sys.path.insert(0, os.path.abspath('..'))
import my_module
<强>测试/ my_module_tests.py 强>
import errno
import unittest
import mock
from .context import my_module
@mock.patch('my_module.os')
class MkdirPTests(unittest.TestCase):
def test_with_valid_non_existing_dir(self, mock_os):
my_module.mkdir_p('not_a_dir')
mock_os.makedirs.assert_called_once_with('not_a_dir')
def test_with_existing_dir(self, mock_os):
mock_os.makedirs.side_effect = OSError(errno.EEXIST, 'Directory exists.')
mock_os.path.isdir.return_value = True
my_module.mkdir_p('existing_dir')
mock_os.path.isdir.assert_called_once_with('existing_dir')
def test_with_permissions_error(self, mock_os):
mock_os.makedirs.side_effect = OSError(errno.EPERM, 'You shall not pass!')
with self.assertRaises(OSError):
my_module.mkdir_p('forbidden_dir')