Below is a simple class with two methods: the first calls open()
to read in a file. The second calls the first method and does error handling.
There is also a corresponding test class that tests the first methods returns data as expected and the other methods test the error handling of potential exceptions thrown by open
.
Firstly, I would like to know if these tests are written in the appropriate manner using python3, mocking and patching as I am new to the language and especially to testing.
I also have a query to why mocking an exception to be thrown cannot be handled like the rest of the tests (see last test method)
fileMethods.py
# -*- coding: utf-8 -*-
def readconfig(myfile):
try:
filecontent = readfile(myfile)
# manipulation of filecontent
except FileNotFoundError:
filecontent = "FileNotFoundError"
except PermissionError:
filecontent = "PermissionError"
return filecontent
def readfile(myfile):
with open(myfile, 'r') as file:
filecontent = file.read()
file.close()
return filecontent
fileMethods_test.py
# -*- coding: utf-8 -*-
import io
import unittest
import unittest.mock as mock
import packageName.fileMethods
class TestIO(unittest.TestCase):
def test_readfile_returns_string(self):
mock_file_content = io.StringIO('Content in file')
with mock.patch('packageName.fileMethods.open', return_value=mock_file_content, create=True):
result = packageName.fileMethods.readfile('file_to_readin')
self.assertEqual('Content in file', result)
def test_readconfig_returns_content(self):
with mock.patch('packageName.fileMethods.readfile', return_value="string", create=True):
result = packageName.fileMethods.readconfig('file_to_readin')
self.assertEqual('string', result)
def test_readconfig_handles_FileNotFoundError(self):
with mock.patch('packageName.fileMethods.readfile', side_effect=FileNotFoundError, create=True):
result = packageName.fileMethods.readconfig('file_to_readin')
self.assertEqual('FileNotFoundError', result)
def test_readconfig_handles_PermissionError(self):
with mock.patch('packageName.fileMethods.readfile', side_effect=PermissionError, create=True):
result = packageName.fileMethods.readconfig('file_to_readin')
self.assertEqual('PermissionError', result)
# Does not work
def test_readconfig_throws_OSError(self):
with mock.patch('packageName.fileMethods.readfile', side_effect=OSError, create=True):
self.assertRaises(OSError, packageName.fileMethods.readconfig('file_to_readin'))
1 Answer 1
The design of the readconfig()
function is seriously problematic. It makes no sense to convert caught exceptions into data, as if the file literally contained the string "FileNotFoundError"
or "PermissionError"
. If you don't have a good way to handle an exception, the right thing to do is let it propagate.
The readfile()
function should be simpler:
def read_file(path):
with open(path) as file:
return file.read()
To note:
- Since "read file" is two words in English, it should not be written as a compound word.
myfile
could be better named. It's a filesystem path, not a file handle. Also, who is "me" in this case?- The
'r'
mode is the default. - You don't need to call
file.close()
on an already closed file. The whole point of thewith
block is that the file is automatically closed when exiting the block.
-
\$\begingroup\$ Thanks for the feedback especially with my
read_file
method. I do not intent to return the error types of a string in an application. I was trying to understand how to test and account for exceptions thrown in a method/function which is used. If like you say I let the error propagate like i did in theread_file
method how would I test that an error has been thrown? I attempted to do this in the last test methodtest_readconfig_throws_OSError
which does not work. \$\endgroup\$SJC– SJC2016年08月01日 18:55:41 +00:00Commented Aug 1, 2016 at 18:55 -
1\$\begingroup\$ On Code Review, we take your posted code literally and seriously. Anyway, the answer is not hard to find. \$\endgroup\$200_success– 200_success2016年08月01日 18:58:04 +00:00Commented Aug 1, 2016 at 18:58
Explore related questions
See similar questions with these tags.