Why does mocking 'open' and returning a FileNotFoundError raise AttributeError: __exit__?

半世苍凉 提交于 2019-12-11 02:26:42

问题


Testing by mocking open with a FileNotFoundError raises AttributeError: __exit__. Why is this happening and what can I do to fix it?

The following code opens a simple text file. If the file is missing it generates a default value. It has been checked by regular running and it appears to be working perfectly.

so_main.py

import os

import so_config


def load_savelocation():
    path = os.path.join(so_config.ROOT, so_config.SAVELOCATION_FN)
    savelocation_path = os.path.normpath(path)
    try:
        with open(savelocation_path) as f:
            so_config.SAVELOCATION_PATH = f.readline()
    except FileNotFoundError:
        so_config.SAVELOCATION_PATH = so_config.ROOT

so_config.py

import os

ROOT, _ = os.path.split(__file__)
SAVELOCATION_PATH = None
SAVELOCATION_FN = 'savelocation.ini'

The unittests are a different story. I've mocked the open command in so.main. test_so_main.py has two tests: One for normal opening of a file which is present and a second to test the FileNotFoundError handling.

The first test of regular file opening test_read_path_from_disk_file_into_config_py works fine.

The second test fails because the FileNotFoundError raises AttributeError: __exit__. I can set self.mock_open.return_value to FileNotFoundError or I can set it to 'garbage'. It doesn't make any difference.

test_so_main.py

import unittest
import unittest.mock as mock

import so_config
import so_main


class TestReadSaveLocation(unittest.TestCase):
    def setUp(self):
        self.savelocation_path = so_config.SAVELOCATION_PATH
        self.root = so_config.ROOT
        so_config.ROOT = 'program root'
        p = mock.patch('so_main.open')
        self.mock_open = p.start()
        self.addCleanup(p.stop)

    def tearDown(self):
        so_config.SAVELOCATION_PATH = self.savelocation_path
        so_config.ROOT = self.root

    def test_read_path_from_disk_file_into_config_py(self):
        self.mock_open().__enter__().readline.return_value = 'data files location'
        so_main.load_savelocation()
        self.assertEqual('data files location', so_config.SAVELOCATION_PATH)

    def test_missing_file_defaults_savelocation_to_program_root(self):
        self.mock_open.return_value = FileNotFoundError
        so_main.load_savelocation()
        self.assertEqual('program root', so_config.SAVELOCATION_PATH)

I'm running Python 3.5.2 via PyCharm 2016.2.1 on a Windows 7 machine.


回答1:


You mock the function to return an exception instead of raise it.

Try using side_effect (docs):

self.mock_open.side_effect = FileNotFoundError


来源:https://stackoverflow.com/questions/38918748/why-does-mocking-open-and-returning-a-filenotfounderror-raise-attributeerror

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!