3 votes

Où est-ce que je me trompe avec Parcheando une fonction avec mock_open ?

J'ai une fonction qui appelle une sous-fonction pour ouvrir un fichier. J'essaie de tester la fonction parentale, mais je veux corriger la sous-fonction et lui faire renvoyer les données que je lui passe (comme si elle lisait un fichier).

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

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)

L'erreur

J'essaie de corriger reversed_lines() en utils.py au sein de la read_log() mais read_log() est toujours lu à partir du journal actuel, indiquant que je ne suis pas Parcheando. reversed_lines() correctement.

Quand je change

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

à

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

Je reçois

======================================================================
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'

Où est-ce que je me trompe ?

2voto

azundo Points 4972

En suivant l'exemple de la documentation à l'adresse https://docs.python.org/3.3/library/unittest.mock.html#mock-open Je pense que vous voulez

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

Cependant, en lisant la source de mock_open : https://github.com/python/cpython/blob/3.7/Lib/unittest/mock.py#L2350

Il semble que le tell pour les filehandles n'est pas implémentée par le mock. Les seules méthodes supportées sont read , readline , readlines , write et en itérant sur le contenu. Vous devrez configurer manuellement l'objet fantaisie pour la fonction tell méthode. Il ne s'agit pas d'une mise en œuvre générale, mais elle fonctionnera dans votre cas spécifique :

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)
        ...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X