2013-04-17 2 views
12

나는 모듈에서 클래스를 가져온,하지만 난 그것이 내가 유형의 오류 얻을 접두사로 모듈의없이 클래스 이름을 패치 할 때 : 예를 들어패치 - 상대 패치 대상 이름이 작동하지 않는 이유는 무엇입니까?

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("notification.models.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("Channel") 
    def testAddChannelWithNamePutsChannel(self, *args): 
     addChannelWithName("channel1") 
     Channel.put.assert_called_with() 

코드의 두 번째 버전이 나에게 유형의 오류를 제공하지 않지만? 왜 다른 곳에서 채널을 그냥 "채널"로 참조 할 수 있습니까? 그렇지만 패치를 위해 오류가 발생하지 않도록 모듈 접두사가 필요합니까? 또한, Channel.put.assert_called_with()를 호출 할 때 assert_called_with가 Channel.put의 특성이 아니기 때문에 전체 모듈 접두사를 제공하는 것이 효과가 없다고 생각합니다. 누군가 무슨 일이 일어 났는지 설명 할 수 있습니까? 많이 고마워!

target should be a string in the form ‘package.module.ClassName’. The target is imported and the specified object replaced with the new object, so the target must be importable from the environment you are calling patch from. The target is imported when the decorated function is executed, not at decoration time.

"Channel" 그냥 문자열이며, patch 적절한 클래스를 찾을 수있는 충분한 정보를 가지고 있지 않습니다

답변

16

patch 장식은 documentation에 명시된 바와 같이, 전체 점선 경로로 대상을 필요로한다. 다른 곳에서 사용하는 Channel이라는 이름과 같지는 않습니다. 모듈 상단에 가져옵니다.

채널이 테스트 모듈 에서 가져 오기 때문에 두 번째 테스트가 실패한 경우 패치는 notification.models의 채널을 mock 객체로 바꿉니다. 어떤 패치는 실제로 객체를 변경하는 것입니다 이름 notification.models 안에 사용 된 채널이 가리키는 곳입니다. 테스트 모듈의 채널 이름은 이미 정의되었으므로 영향을받지 않습니다. 이것은 실제로 더 나은 여기에 설명 : 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") 
+0

매우 설명적이고 두 가지 질문에 모두 답변했습니다. 고맙습니다. – golmschenk

+0

세 번째 옵션은 객체의 메소드뿐만 아니라 모듈의 전체 클래스를 조롱하는 데에도 사용됩니다. 고맙습니다! – balu

관련 문제