2016-05-06 6 views
6

Ich verstehe, dass, wenn Go-Code so strukturiert ist, dass es auf Schnittstellen programmiert ist, ist es trivial zu verspotten; Ich arbeite jedoch mit einer Codebasis, die ich nicht ändern kann (das ist nicht meine), und das ist nicht der Fall.Golang Affe Patching

Diese Codebasis ist stark miteinander verbunden und nichts ist auf eine Schnittstelle programmiert, nur Strukturen, also keine Abhängigkeitsinjektion.

Die Strukturen selbst enthalten nur andere Strukturen, also kann ich auch nicht auf diese Weise ausspionieren. Ich glaube nicht, dass ich irgendetwas mit Methoden machen kann, und die wenigen Funktionen, die es gibt, sind keine Variablen, also gibt es keine Möglichkeit, dass ich sie austausche. Vererbung ist keine Sache in Golang, so dass auch ein Nein ist.

In Skriptsprachen wie Python können wir die Objekte zur Laufzeit ändern, auch bekannt als Affe-Patch. Gibt es etwas Vergleichbares, das ich in Golang machen kann? Versuchen, einen Weg zum Testen/Benchmarking zu finden, ohne den zugrunde liegenden Code zu berühren.

Antwort

3

Wenn ich in diese Situation gerannt bin, ist mein Ansatz, meine eigene Schnittstelle als Wrapper zu verwenden, der in Tests Spott erlaubt. Beispielsweise.

type MyInterface interface { 
    DoSomething(i int) error 
    DoSomethingElse() ([]int, error) 
} 

type Concrete struct { 
    client *somepackage.Client 
} 

func (c *Concrete) DoSomething(i int) error { 
    return c.client.DoSomething(i) 
} 

func (c *Concrete) DoSomethingElse() ([]int, error) { 
    return c.client.DoSomethingElse() 
} 

Jetzt können Sie den Beton in der gleichen Art und Weise verspotten Sie somepackage.Client verspotten würde, wenn es auch eine Schnittstelle waren.

Wie in den Kommentaren unten von @elithrar hingewiesen, können Sie den Typ einbetten, den Sie verspotten möchten, so dass Sie nur gezwungen werden, Methoden hinzuzufügen, die Mocking benötigen. Zum Beispiel:

type Concrete struct { 
    *somepackage.Client 
} 

Wenn wie das getan, zusätzliche Methoden wie DoSomethingNotNeedingMocking könnten direkt auf Concrete ohne aufgerufen werden sie an die Schnittstelle hinzufügen/verspotten es heraus.

+0

Ich möchte sicherstellen, dass ich das richtig verstehe. Sie schlagen vor, eine Struct-Wrapping-Struktur zu definieren, mit der ich es zu tun habe. Definieren Sie Methoden für diese neu eingeführte Struktur, die die Methoden der umhüllten Struktur aufrufen. Definieren Sie eine Schnittstelle über die Wrapper-Struktur, und spionieren Sie dann selektiv jede Teilmenge der zugrundeliegenden Logik aus, die mokiert werden soll. Wenn meine Interpretation korrekt ist, scheint es, als würde ich den gesamten Code neu schreiben, vorausgesetzt, dass er so eng ist. Vielleicht ist das zu erwarten - schätze, es gibt vielleicht keine Alternative. –

+0

Das, so unglücklich es auch sein mag, ist genau das, was ich vorschlage. – sberry

+1

Sie müssen die Methoden, die Sie nicht überschreiben müssen, nicht aufrufen/vortäuschen. Sie einbetten den ursprünglichen Typ in Ihrem Typ, der die Methoden fördert, und überschreiben dann nur die Methoden, die Sie möchten: https://play.golang.org/p/oHW1JX8iFb – elithrar