2016-07-14 13 views
1

ich mit einigen Prototyp-Code begann, die in diese Richtung geht:Ist die Testimplementierung beim Entwerfen der Klasse, die die externe API aufruft, korrekt?

// Omitted most definitions, return values checks, etc. 
// The real code is much bigger and uglier. 
serverId = socket(AD_INET, SOCK_STREAM, PROTO_ANY); 
setsockopt(serverId, SOL_SOCKET, SO_REUSEADDR, &reuseAddrOk, sizeof(int)); 
bind(serverId, &serverAddress, sizeof(serverAddress)); 
listen(serverId, waitQueueSize); 
clientId = accept(serverId, &clientAddress, sizeof(clientAddress)); 
read(clientId, clientBuffer, charsToRead); 

nun in sehr einfachen Klassen Extrahieren Funktionalität diesen Code Refactoring wie der Versuch, ich würde (nicht für die Dinge jetzt sehr allgemein zu machen ... YAGNI). Dies ist die Art von Interface Ich denke an:

SocketServer server = SocketServer(parameters); 
// SocketServer knows how to create a SocketClient...abstract factories, dependency injection, etc. etc. 
SocketClient client = server.accept(); 
string clientMessage = client.read(); 
client.write(serverMessage); 

Zum Beispiel der SocketServer Klasse kapselt alle Textvorschlag für einen neuen Socket-Server zu erstellen:

SocketServer server = SocketServer(parameters); 

Dann wird, da diese Notwendigkeit zu nennen die System-API, ich muss es nachspionieren:

SocketServer server = SocketServer(systemAPI, parameters); 

Nun, was bedeutet es zu testen, dass dieser Code korrekt ist? Es erzeugt keine Ausgabe, die ich überprüfen kann (oder besser, ich mache das alles genau, um die Ausgabe zu kapseln, wie Dateideskriptoren). Ich konnte überprüfen, ob die richtigen Methoden der Mock-API genannt werden, wie:

testSocketCalledWithCorrectParameters() { 
    systemAPI = mock(SystemAPI).expect(once()).method("socket").with(
     SystemAPI.AF_INET, 
     SystemAPI.SOCK_STREAM, 
     SystemAPI.PROTO_AUTO 
    ); 
    ServerSocket(systemAPI, parameters); 
} 

Ist das eine richtige Situation, wo ich für den Test des Implementierung statt einer Schnittstelle verlassen sollte? Ist man gezwungen, eine Implementierung zu testen, anstatt eine Schnittstelle, die nach schlechtem Design riecht?

Alle anderen Tests, die ich von Satz Erwartungen an die Umsetzung denken konnte:

testServerSocketIsCreatedWithCorrectDescriptor() { 
    dummyDescriptor = 10; 
    systemAPI = mock(SystemAPI).when("socket").return(dummyDescriptor); 
    server = SocketServer(systemAPI, parameters); 
    assertEquals(dummyDescriptor, server.descriptor); 
} 

/** 
* @expected SocketException 
*/ 
testThrowsExceptionIfErrorCreatingSocket() { 
    systemAPI = mock(SystemAPI).when("socket").return(SystemAPI.RETURN_ERROR); 
    SocketServer(systemAPI, parameters); 
} 

// etc. 

Und dann sollte ich schreiben Unit-Tests auch für die socketAPI, oder sollte ich nur für selbstverständlich, dass es ein sehr sein Klasse "stack wrapper", die nur Aufrufe an die externe API delegiert (und somit nicht getestet werden muss)?

+0

Wenn 'X'' Y' machen soll, wenn 'Z' geliefert wird, wie würdest du es testen? Sie rufen 'X' auf, liefern' Y' und testen das Ergebnis für 'Z'. Wenn Sie nicht können, müssen Sie die grundlegende Infrastruktur schreiben, die Ihnen dies ermöglicht. –

+0

"* Testen einer Implementierung anstelle einer Schnittstelle *" - Was würde es bedeuten, eine Schnittstelle zu testen? –

+0

@OliverCharlesworth Wenn ich eine Funktion 'add (a, b)' habe, kann ich 'add (1,2) == 3' und' add (10,1) == 11' testen, unabhängig davon, wie diese Funktion ist implementiert. – swahnee

Antwort

0

Lassen Sie mich versuchen, eins nach dem anderen zu beantworten.

1. Aufruf Testing Eigenschaften

Diese Art von Test hat nur dokumentarischen Wert (Dies ist der Weg, um die API aufrufen.) Überprüfen Sie, ob es wirklich wert ist -> vielleicht die Aussage klar genug in deinem Code.

2. testServerSocketIsCreatedWithCorrectDescriptor:

Für mich ist diese Art von Test mehr Wert haben. Ich schreibe fast immer eine testCreation, die zeigt: Eingabeparameter und behauptet Eigenschaften, z.B. Ein Auto benötigt ein Rad für den Bau und hat dann standardmäßig 4 Räder, rote Farbe und ein Lenkrad.

3. testThrowsExceptionIfErrorCreatingSocket

Diese Art von Tests sind die wertvollsten. Sie definieren und schützen das Verhalten Ihrer Klasse unter verschiedenen Umständen. Ich vermisse hier eine Behauptung, z.B. die Art der Ausnahme, die ausgelöst wird. Schreiben Sie so viel wie möglich über diese Art von Tests.

4.TestsystemAPI

Nein. Testen Sie niemals das Systemverhalten in Komponententests. Vor allem nicht mit Mocks. Dies ist Teil von Modul- oder End-to-End-Tests.

Hoffe, das hilft.

+0

Danke für deine Antwort. Was meinst du mit "Call-Eigenschaften testen"? Testen, dass bestimmte Methoden des Mocks eine bestimmte Anzahl von Zeiten genannt werden? Denken Sie im Fall 2, dass es sich lohnt, Eigenschaften zu veröffentlichen, die normalerweise (nur als Teil der Implementierung) nur zu Testzwecken versteckt werden würden? Vereinbart, sich stärker auf das Testen außergewöhnlicher Umstände zu konzentrieren. – swahnee

+0

Ja, ich meinte testen, dass bestimmte Methoden auf einem Schein aufgerufen werden, und welche Argumente übergeben werden. Im Fall 2: Sie wollten Server.descriptor nur zu Testzwecken enthüllen - keine gute Idee. Mein Tipp: Hören Sie sich Ihre Tests an, die oft gravierende Designfehler aufweisen. Wenn das Testen hart und gruselig ist - es ist Ihr Design, nicht die Schuld des Tests – mrAtari