简体   繁体   English

使用mock_open修补函数我在哪里出错了?

[英]Where am I going wrong with patching a function with mock_open?

I have a function that calls a sub-function to open up a file. 我有一个函数调用子函数来打开文件。 I am trying to test the parent function, but I want to patch the sub-function and have it return the data I pass in (as if it read from a file). 我正在尝试测试父函数,但我想修补子函数并让它返回我传入的数据(就好像它从文件中读取)。

tests.py tests.py

# Read in the sample data
__SAMPLE_LOG = os.path.join(settings.BASE_DIR, "apps/tests/log_viewer/sample_logs/sample_manager_log.log")
sample_data = []
for line in reversed_lines(open(__SAMPLE_LOG)):
    sample_data.append(line)

sample_data = ('').join(sample_data)

class ReadLog(TestCase):
    @patch('apps.log_viewer.utils.reversed_lines', new_callable = mock_open, read_data = sample_data)
    def test_returnsDictionaryContainingListOfDictionaries(self, mock_file):
        activity = read_log()

        # Make sure the sample data was read ==> this fails.
        self.assertEqual(open(settings.ACTIVITY_LOG_FILE).read(), sample_data)

utils.py utils.py

def read_log():

   # This is the line I am trying to patch
   for line in reversed_lines(open(settings.ACTIVITY_LOG_FILE)):      
      # process data

# see: https://stackoverflow.com/questions/260273/most-efficient-way-to-search-the-last-x-lines-of-a-file-in-python/260433#260433
def reversed_lines(file):
    "Generate the lines of file in reverse order."
    part = ''
    for block in reversed_blocks(file):
        for c in reversed(block):
            if c == '\n' and part:
                yield part[::-1]
                part = ''
            part += c
    if part: yield part[::-1]

def reversed_blocks(file, blocksize=4096):
    "Generate blocks of file's contents in reverse order."
    file.seek(0, os.SEEK_END)
    here = file.tell()
    while 0 < here:
        delta = min(blocksize, here)
        here -= delta
        file.seek(here, os.SEEK_SET)
        yield file.read(delta)

The error 错误

I am trying to patch reversed_lines() in utils.py within the read_log() method, but read_log() is still reading from the actual log, indicating that I am not patching reversed_lines() correctly. 我试图修补reversed_lines()utils.py的内read_log()方法,但read_log()仍然从实际日志阅读,表明我不是修补reversed_lines()正确。

When I change 当我改变

@patch('apps.log_viewer.utils.reversed_lines', new_callable = mock_open, read_data = sample_data)

to

@patch('builtins.open', new_callable = mock_open, read_data = sample_data)

I get 我明白了

======================================================================
ERROR: test_returnsDictionaryContainingListOfDictionaries 
(tests.log_viewer.test_utils.ReadLog)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/mock.py", line 1209, in patched
    return func(*args, **keywargs)
  File "/webapp/apps/tests/log_viewer/test_utils.py", line 32, in test_returnsDictionaryContainingListOfDictionaries
    activity = read_log()
  File "/webapp/apps/log_viewer/utils.py", line 64, in read_log
    for line in reversed_lines(open(settings.ACTIVITY_LOG_FILE)):
  File "/webapp/apps/log_viewer/utils.py", line 173, in reversed_lines
    for block in reversed_blocks(file):
  File "/webapp/apps/log_viewer/utils.py", line 164, in reversed_blocks
    while 0 < here:
TypeError: '<' not supported between instances of 'int' and 'MagicMock'

Where am I going wrong? 我哪里错了?

Following the example from the docs at https://docs.python.org/3.3/library/unittest.mock.html#mock-open I think you want 按照https://docs.python.org/3.3/library/unittest.mock.html#mock-open上的文档示例,我认为你想要的

@patch('builtins.open', mock_open(read_data = sample_data), create=True)

However reading through the source of mock_open : https://github.com/python/cpython/blob/3.7/Lib/unittest/mock.py#L2350 然而,阅读mock_open的源mock_openhttps//github.com/python/cpython/blob/3.7/Lib/unittest/mock.py#L2350

It appears that the tell method for filehandles is not implemented by the mock. 看起来mock文件的tell方法没有实现。 The only supported methods are read , readline , readlines , write and iterating over the contents. 唯一支持的方法是readreadlinereadlineswrite并遍历内容。 You'll need to manually set up the mock for the tell method. 您需要为tell方法手动设置模拟。 This is not a general implementation but will work in your specific case: 这不是一般的实现,但可以在您的特定情况下工作:

class ReadLog(TestCase):
    @patch('builtins.open', mock_open(read_data = sample_data), create=True)
    def test_returnsDictionaryContainingListOfDictionaries(self, mock_file):
        mock_file.return_value.tell.return_value = len(sample_data)
        ...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM