2014-09-28 9 views
7

Wenn ich Klassen oder Methoden verspotte, wenn ich Unitests in Python schreibe, warum brauche ich @patch Dekorator? Ich könnte nur die Methode mit Mock-Objekt ohne Patch-Annotation ersetzen.Python unittest: to mock.patch() oder ersetzen Sie einfach Methode mit Mock?

Beispiele:

class TestFoobar(unittest.TestCase): 
def setUp(self): 
    self.foobar = FooBar() 

# 1) With patch decorator: 

@patch.object(FooBar, "_get_bar") 
@patch.object(FooBar, "_get_foo") 
def test_get_foobar_with_patch(self, mock_get_foo, mock_get_bar): 
    mock_get_bar.return_value = "bar1" 
    mock_get_foo.return_value = "foo1" 

    actual = self.foobar.get_foobar() 

    self.assertEqual("foo1bar1", actual) 

# 2) Just replacing the real methods with Mock with proper return_value: 

def test_get_foobar_with_replacement(self): 
    self.foobar._get_foo = Mock(return_value="foo2") 
    self.foobar._get_bar = Mock(return_value="bar2") 

    actual = self.foobar.get_foobar() 

    self.assertEqual("foo2bar2", actual) 

Könnte jemand ein Beispiel produzieren, wo Patch Dekorateur gut ist und ersetzt ist schlecht?

Wir haben immer Patch-Dekorator mit unserem Team verwendet, aber nachdem ich this comment für einen Beitrag gelesen hatte, kam ich auf die Idee, dass wir vielleicht besser aussehenden Code schreiben könnten, ohne Patch-Dekorierer.

Ich verstehe, dass das Patchen temporär ist, also ist es in einigen Fällen gefährlich, nicht den Patch Decorator zu verwenden und Methoden stattdessen mit Mock zu ersetzen? Könnte es sein, dass das Ersetzen von Objekten in einer Testmethode das Ergebnis der nächsten Testmethode beeinflussen kann?

Ich habe versucht, dies zu beweisen, kam aber leer aus: Beide Tests bestehen in den nächsten Code:

def test_get_foobar_with_replacement(self): 
    self.foobar._get_foo = Mock(return_value="foo2") 
    self.foobar._get_bar = Mock(return_value="bar2") 

    actual = self.foobar.get_foobar() 

    self.assertIsInstance(self.foobar._get_bar, Mock) 
    self.assertIsInstance(self.foobar._get_foo, Mock) 
    self.assertEqual("foo2bar2", actual) 

def test_get_foobar_with_real_methods(self): 

    actual = self.foobar.get_foobar() 

    self.assertNotIsInstance(self.foobar._get_bar, Mock) 
    self.assertNotIsInstance(self.foobar._get_foo, Mock) 
    self.assertIsInstance(self.foobar._get_bar, types.MethodType) 
    self.assertIsInstance(self.foobar._get_foo, types.MethodType) 
    self.assertEqual("foobar", actual) 

Der vollständige Quellcode (Python 3.3): dropbox.com/s/t8bewsdaalzrgke/test_foobar.py? dl = 0

Antwort

4

patch.object wird das Element wiederherstellen, das Sie in den ursprünglichen Zustand gepatcht haben, nachdem die Testmethode zurückgegeben wurde. Wenn Sie das Objekt selbst reparieren, müssen Sie den ursprünglichen Wert wiederherstellen, wenn dieses Objekt in einem anderen Test verwendet wird.

In Ihren beiden Beispielen patchen Sie eigentlich zwei verschiedene Dinge. Ihr Anruf an patch.object patcht die KlasseFooBar, während Ihr Affe Patch eine spezifische Instanz von FooBar patches.

Das Wiederherstellen des ursprünglichen Objekts ist nicht wichtig, wenn das Objekt jedes Mal neu erstellt wird. (Sie es nicht zeigen, aber ich nehme an self.foobar in einer setUp Methode erstellt wird, so dass, obwohl Sie seine _get_foo Methode ersetzen, Sie Wiederverwendung nicht, dass spezifisches Objekt in mehreren Tests.)

+0

Ich dachte, Ich habe nur die Methode gepatcht, nicht die Klasse. Ich lese [dies] (http://www.voidspace.org.uk/python/mock/patch.html#patch-object) und wie ich verstanden habe, habe ich die Methode gepatcht, nicht die Klasse. Kannst du mir zeigen, wie es besser geht? – kristjanroosild

+0

"Das Wiederherstellen des ursprünglichen Objekts ist nicht wichtig, wenn das Objekt jedes Mal von Grund auf neu erstellt wird" - Ich verstehe, dass es in Ordnung ist, die Methode einfach durch Mock() zu ersetzen und kein Patching zu verwenden, solange Sie das wiederverwendbare Objekt erstellen Objekte in der Methode setUp. Ich habe ein Beispiel gemacht, bei dem der zweite Test einen Assertionsfehler bekommt - der Test erwartet, dass die Methode keine Instanz von Mock ist, aber das ist, weil das foobar-Objekt außerhalb der Testklasse erstellt wurde, nicht in der setUp-Methode: https: // www.dropbox.com/s/p1djmm9bv7op25q/test_foobar2.py?dl=0 – kristjanroosild

Verwandte Themen