How do I write a unit test for OSError?
我有以下要测试的python代码:
1 2 3 4 5 6 7 | 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 |
我想在单元测试中做如下的事情。
1 2 3 4 | def test_find_or_make_logfolder_pre_existing(self): with self.assertRaises(OSError): makedirs(self.logfolder) find_or_make_logfolder() |
但是,
我该如何测试这个,还是真的需要测试这个?
当覆盖率为100%时,我倾向于喜欢它。
模拟
side_effect allows you to perform side effects, including raising an
exception when a mock is called
1 2 3 4 5 6 7 | 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) |
你可以走一条更Python的路线来达到这个目的。在Python中,哲学是
It's better to ask for forgiveness than to ask for permission.
在这里见到EAFP
考虑到这一点,您的代码可以编写如下:
1 2 3 4 5 6 | def find_or_make_logfolder(self): try: makedirs(self.logfolder) except OSError: #self.logfolder was already a directory, continue on. pass |
现在为了100%地覆盖这些代码,您只需要在目录已经存在的地方创建一个测试用例。
我在这里发布得很晚,但我想分享我的解决方案(基于这个答案),还包括我的
我做了一个函数来创建一个路径,如果它不存在的话,比如
Myo-模
1 2 3 4 5 6 7 8 9 10 11 12 | 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 |
如果
我通过模拟
测试/上下文.py
1 2 3 4 5 | import sys import os sys.path.insert(0, os.path.abspath('..')) import my_module |
测试/我的模块测试.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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') |
还有许多其他情况会引发OSError,例如文件系统已满、权限不足、文件已存在等。
在这种情况下,权限很容易被利用——只需将
1 2 3 | >>> import os >>> os.makedirs('/somedir') OSError: [Errno 13] Permission denied: '/somedir' |
另外,考虑一下MartinKonecny建议的重构。