I have a productive function that read a file and in some situations also write (more than once) to another file (with kind of detailed error output).
I am able to mock the file reading and give specific file content in the unittests. But I do not know how to test for what was written to the the second file which is also mocked via mock_open().
One important point is that I am not interested in writing a real file to the filesystem when unittesting.
That is the productive code:
import pathlib
def my_prod_code(fp):
with fp.open('r') as if:
result = if.read()
with fp.with_suffix('.error.out').open('w') as of:
of.write(f'Read {result}.')
of.write('FIN.')
return result
That is the unittest
import unittest
from unittest import mock
import pathlib
class MyTest(unittest.TestCase):
def test_foobar(self, mock_unlink):
opener = mock.mock_open(read_data='foobar')
with mock.patch('pathlib.Path.open', opener):
result = my_prod_code(pathlib.Path('file.in'))
self.assertEqual(result, 'foobar')
# Want to check for the written content also
CodePudding user response:
There is no built-in way to do this, so you either have to add your own handling in the mock, or use some package that fakes the file system.
Adding your own handling would mean to implement your own write, e.g. something like this:
class MockWriter:
"""Collect all written data."""
def __init__(self):
self.contents = ''
def write(self, data):
self.contents = data
class MyTest(unittest.TestCase):
def test_foobar(self):
opener = mock.mock_open(read_data='foobar')
writer = MockWriter()
# replace the write method in the mock with your own
opener.return_value.write = writer.write
with mock.patch('pathlib.Path.open', opener) as f:
result = my_prod_code(pathlib.Path('file.in'))
self.assertEqual(result, 'foobar')
self.assertEqual(writer.contents, 'Read foobar.FIN.')
The other possibility is to use a fake file system like pyfakefs:
from pyfakefs.fake_filesystem_unittest import TestCase
class MyTest(TestCase):
def setUp(self):
self.setUpPyfakefs()
def test_foobar(self):
self.fs.create_file('file.in', contents='foobar')
result = my_prod_code(pathlib.Path('file.in'))
self.assertEqual(result, 'foobar')
path = pathlib.Path('file.error.out')
self.assertEqual(path.read_text(), 'Read foobar.FIN.')
This way, you don't have to do the mocking yourself and can use the standard file system functions, with the downside that you need an extra package that generates some test overhead.
Disclaimer:
I'm a contributor to pyfakefs.
