2012-05-25 5 views
20

OK,
Ich weiß, dass dies in der manual erwähnt wird, und wahrscheinlich mit side_effect und/oder return_value zu tun hat, aber ein einfaches, direktes Beispiel wird mir immens helfen.Wie spionieren Sie eine Python-Klasse und erhalten Sie für jede Instanz ein neues Mock-Objekt?

ich habe:

class ClassToPatch(): 
    def __init__(self, *args): 
     _do_some_init_stuff() 

    def some_func(): 
     _do_stuff() 


class UUT(): 
    def __init__(self, *args) 
     resource_1 = ClassToPatch() 
     resource_2 = ClassToPatch() 

Nun, ich Komponententest die UUT Klasse wollen, und verspotten die ClassToPatch. Wenn man die UUT Klasse kennt, werden genau zwei ClassToPatch Objekte instanziiert. Ich möchte, dass das Mock-Framework ein neues Mock-Objekt für jede Instantiierung zurückgibt, so dass ich später die Aufrufe für jede separat aktivieren kann.

Wie erreiche ich dies mit dem @patch Dekorateur in einem Testfall? Nämlich, wie das folgende Codebeispiel zu beheben?

class TestCase1(unittest.TestCase): 

    @patch('classToPatch.ClassToPatch',autospec=True) 
    def test_1(self,mock1,mock2): 
     _assert_stuff() 

Antwort

21

Hier ist ein Beispiel quick'n'dirty Sie gehend zu erhalten:

import mock 
import unittest 

class ClassToPatch(): 
    def __init__(self, *args): 
     pass 

    def some_func(self): 
     return id(self) 

class UUT(): 
    def __init__(self, *args): 
     resource_1 = ClassToPatch() 
     resource_2 = ClassToPatch() 
     self.test_property = (resource_1.some_func(), resource_2.some_func()) 

class TestCase1(unittest.TestCase): 
    @mock.patch('__main__.ClassToPatch', autospec = True) 
    def test_1(self, mock1): 
     ctpMocks = [mock.Mock(), mock.Mock()] 
     ctpMocks[0].some_func.return_value = "funky" 
     ctpMocks[1].some_func.return_value = "monkey" 
     mock1.side_effect = ctpMocks 

     u = UUT() 
     self.assertEqual(u.test_property, ("funky", "monkey")) 

if __name__ == '__main__': 
    unittest.main() 

Ich habe test_property mit dem Prüfobjekt hinzugefügt, so dass das Gerät zu testen, etwas Nützliches tut. Nun, ohne den Schein test_property sollte ein Tupel sein, das die Ids der beiden ClassToPatch Instanzen enthält. Aber mit dem Mock sollte es das Tupel sein: ("funky", "monkey").

Ich habe die side_effect-Eigenschaft des Mock-Objekts verwendet, sodass bei jedem Aufruf im Initializer UUT eine andere Instanz von ClassToPatch zurückgegeben wird.

Hoffe, das hilft.

Edit: Oh, übrigens, wenn ich das Gerät Test laufen erhalte ich:

. 
---------------------------------------------------------------------- 
Ran 1 test in 0.004s 

OK 
+0

(Neu Python :) Jede Art und Weise, dies zu ändern, unter Python 2.7 zu arbeiten? –

+0

Ich habe gerade diesen Code in Python 2.7.9 (win32) ausgeführt und es hat gut funktioniert. Welchen Fehler bekommst du? – srgerg

+0

~ $ python --version Python 2.7.5 AttributeError: hat nicht das Attribut 'ClassToPatch' –

Verwandte Themen