0

Я недавно узнал о unittest.monkey.patch и его вариантах, и я хотел бы использовать его для модульного тестирования на атомарность функции чтения файла. Однако патч не имеет никакого эффекта.Как исправить метод io.RawIOBase.read с помощью unittest?

Вот моя настройка. Метод под наблюдением примерно вот так (abriged):

#local_storage.py 

def read(uri): 
    with open(path, "rb") as file_handle: 
     result = file_handle.read() 
    return result 

И модуль, который выполняет модульные тесты (также abriged):

#test/test_local_storage.py 

import unittest.mock 
import local_storage 

def _read_while_writing(io_handle, size=-1): 
    """ The patch function, to replace io.RawIOBase.read. """ 

    _write_something_to(TestLocalStorage._unsafe_target_file) #Appends "12". 
    result = io_handle.read(size) #Should call the actual read. 
    _write_something_to(TestLocalStorage._unsafe_target_file) #Appends "34". 

class TestLocalStorage(unittest.TestCase): 
    _unsafe_target_file = "test.txt" 

    def test_read_atomicity(self): 
     with open(self._unsafe_target_file, "wb") as unsafe_file_handle: 
      unsafe_file_handle.write(b"Test") 

     with unittest.mock.patch("io.RawIOBase.read", _read_while_writing): # <--- This doesn't work! 
      result = local_storage.read(TestLocalStorage._unsafe_target_file) #The actual test. 
      self.assertIn(result, [b"Test", b"Test1234"], "Read is not atomic.") 

Таким образом, патч должен гарантировать, что каждый раз, когда вы попробуйте прочитать его, файл будет изменен непосредственно перед и сразу после фактического чтения, как если бы это произошло одновременно, таким образом, проверяя атомарность нашего чтения.

В настоящее время удаленный тест работоспособности завершен, но я проверял с помощью операторов печати, что функция патча фактически не вызвана, поэтому файл никогда не получает дополнительных записей (он просто говорит «Тест»). Я также модифицировал код как неатомный.

Так что мой вопрос: Как я могу исправить функцию дескриптора ввода-вывода в модуле local_storage read? Я читал в другом месте, что люди, как правило, заменяют функцию open(), чтобы возвращать что-то вроде StringIO, но я не вижу, как это может решить эту проблему.

Мне нужно поддерживать Python 3.4 и выше.

+0

вы смотрели, чтобы посмотреть, как издеваться 'open'? Прочтите [это] (http://www.voidspace.org.uk/python/mock/helpers.html#mock-open). Но иногда, да, я также видел, что 'StringIO' используется, чтобы не писать напрямую в файловую систему. – idjaw

+0

В Python 3 он поддерживается [здесь] (https://docs.python.org/3/library/unittest.mock.html#mock-open) – idjaw

+0

Я написал какое-то решение, которое объясняет, как справиться с контекстных менеджеров. Детали вокруг него не совсем связаны с тем, что вы пытаетесь сделать, но объясняют природу контекста и используют открытые. Надеюсь, что это поможет: http: // stackoverflow.com/a/33652204/1832539 – idjaw

ответ

0

Я, наконец, нашел решение самостоятельно.

Проблема в том, что mock не может издеваться над любыми методами объектов, которые записаны в C. Один из них - RawIOBase, с которым я столкнулся.

Действительно, решение заключалось в том, чтобы высмеять open, чтобы вернуть обертку вокруг RawIOBase. Я не мог получить mock для создания обертки для меня, поэтому я внедрил ее сам.

Существует один предопределенный файл, который считается «небезопасным». Обертка записывает этот «небезопасный» файл каждый раз, когда любой вызов делается в оболочку. Это позволяет тестировать атомарность записи файлов, так как при написании она записывает дополнительные вещи в небезопасный файл. Моя реализация предотвращает это, записывая временный («безопасный») файл, а затем перемещая этот файл поверх целевого файла.

Обертка имеет специальный чехол для функции read, потому что для правильной проверки атомарности необходимо записать в файл во время прочитанного. Поэтому он читает сначала на полпути через файл, затем останавливается и что-то пишет, а затем читает. Это решение теперь полужестко закодировано (насколько далеко продвинуто), но я найду способ улучшить это.

Вы можете увидеть мое решение здесь: https://github.com/Ghostkeeper/Luna/blob/0e88841d19737fb1f4606917f86e3de9b5b9f29b/plugins/storage/localstorage/test/test_local_storage.py

 Смежные вопросы

  • Нет связанных вопросов^_^