web-dev-qa-db-fra.com

Python: se moquer d'un gestionnaire de contexte

Je ne comprends pas pourquoi je ne peux pas me moquer de NamedTemporaryFile.name dans cet exemple:

from mock import Mock, patch
import unittest
import tempfile

def myfunc():
    with tempfile.NamedTemporaryFile() as mytmp:
        return mytmp.name

class TestMock(unittest.TestCase):
    @patch('tempfile.NamedTemporaryFile')
    def test_cm(self, mock_tmp):
        mytmpname = 'abcde'
        mock_tmp.__enter__.return_value.name = mytmpname
        self.assertEqual(myfunc(), mytmpname)

Résultats des tests dans:

AssertionError: <MagicMock name='NamedTemporaryFile().__enter__().name' id='140275675011280'> != 'abcde'
45
Willem

Vous définissez la mauvaise maquette: mock_tmp n'est pas le gestionnaire de contexte, mais plutôt renvoie un gestionnaire de contexte. Remplacez votre ligne de configuration par:

mock_tmp.return_value.__enter__.return_value.name = mytmpname

et votre test fonctionnera.

84
Michele d'Amico

Voici une alternative avec pytest et fixateur moqueur , ce qui est également une pratique courante:

def test_myfunc(mocker):
    mock_tempfile = mocker.MagicMock(name='tempfile')
    mocker.patch(__+ '.tempfile', new=mock_tempfile)
    mytmpname = 'abcde'
    mock_tempfile.NamedTemporaryFile.return_value.__enter__.return_value.name = mytmpname
    assert myfunc() == mytmpname
1
Peter K