Подтвердить что ты не робот

Патч - Почему не будет указано имя целевого имени патча?

Я импортировал класс из модуля, но когда я пытаюсь исправить имя класса без его модуля в качестве префикса, я получаю ошибку типа:

TypeError: Need a valid target to patch. You supplied: 'MyClass'

Например, следующий код дает мне ошибку выше:

import unittest
from mock import Mock, MagicMock, patch
from notification.models import Channel, addChannelWithName, deleteChannelWithName, listAllChannelNames

class TestChannel(unittest.TestCase):
    @patch("Channel")
    def testAddChannelWithNamePutsChannel(self, *args):
        addChannelWithName("channel1")
        Channel.put.assert_called_with()

Хотя эта вторая версия кода не дает мне ошибку типа:

import unittest
from mock import Mock, MagicMock, patch
from notification.models import Channel, addChannelWithName, deleteChannelWithName, listAllChannelNames

class TestChannel(unittest.TestCase):
    @patch("notification.models.Channel")
    def testAddChannelWithNamePutsChannel(self, *args):
        addChannelWithName("channel1")
        Channel.put.assert_called_with()

Почему? Почему я могу ссылаться на канал как на "Канал" в других местах, но для патча мне нужен префикс модуля, чтобы не получить ошибку? Кроме того, я чувствую, что предоставление полного модуля префикса не работает либо потому, что когда я вызываю Channel.put.assert_called_with(), я получаю сообщение об ошибке, которое assert_called_with не является атрибутом Channel.put. Может кто-нибудь объяснить, что происходит? Большое вам спасибо!

4b9b3361

Ответ 1

Декоратору patch требуется, чтобы цель была полным пунктирным путем, как указано в документации:

target должна быть строка в форме 'package.module.ClassName. Цель импортируется, и указанный объект заменяется новым объектом, поэтому цель должна быть импортируемой из среды, из которой вы вызываете патч. Цель импортируется, когда оформленная функция выполняется, а не время украшения.

"Channel" - это просто строка, а patch недостаточно информации для поиска соответствующего класса. Это не то же самое, что имя Channel, которое вы используете в другом месте, которое импортируется в верхней части модуля.

Второй тест завершился неудачно, потому что канал импортируется в тестовом модуле , а затем патч заменяет Канал в методах уведомления с макетным объектом. Фактический патч - это изменить объект, на который указывает канал name, используемый в уведомлении. Название Channel в тестовом модуле уже определено, поэтому оно не изменяется. Это на самом деле лучше объясняется здесь: http://www.voidspace.org.uk/python/mock/patch.html#id1

Чтобы получить доступ к исправленной версии вашего объекта, вы можете напрямую обратиться к модулю:

import unittest 
from mock import patch 
from notification.models import Channel, addChannelWithName  
from notification import models 

class TestChannel1(unittest.TestCase): 
    @patch("notification.models.Channel") 
    def testAddChannelWithNamePutsChannel(self, *args): 
        addChannelWithName("channel1") 
        models.Channel.put.assert_called_with("channel1") 

Или используйте исправленную версию, переданную в качестве дополнительного аргумента в декорированную функцию:

class TestChannel2(unittest.TestCase): 
    @patch("notification.models.Channel") 
    def testAddChannelWithNamePutsChannel(self, mock_channel): 
        addChannelWithName("channel1") 
        mock_channel.put.assert_called_with("channel1") 

Если вы просто хотите быстро исправить один метод для объекта, обычно проще использовать декоратор patch.object:

class TestChannel3(unittest.TestCase):
    @patch.object(Channel, 'put')    
    def testAddChannelWithNamePutsChannel(self, *arg): 
        addChannelWithName("channel1") 
        Channel.put.assert_called_with("channel1")