2015-09-07 6 views
5

Ich muss mich zunächst entschuldigen, wenn die verwendeten Begriffe nicht korrekt sind. Ich benutze groovy/java nur für Automatisierungsaufgaben (Gradle), und ich habe keine jahrelange Erfahrung in der Bereitstellung von Software für die Produktion.Spock - Rückgabe des festen Wertes funktioniert nicht wie erwartet

Also, die Herausforderung, die ich habe, ist wie folgt: Ich habe eine Spezifikation, die versucht, eine Rückkehr Zeichenfolge zu testen ist wie erwartet (fast identisch mit this).

def "pretty print returns correct string"() { 
    setup: 
    X509Certificate stubCert = Stub() 
    stubCert.getSubjectDN().toString() >> "Test" 

    when: 
    def output = X509CertificateUtils.prettyPrint(stubCert) 

    then: 
    output == "Subject: Test" 
} 

Allerdings ist der Unterschied, dass meine Methode Constraint ein Hauptziel zurückkehrt und sein dieses Objekt toString(), die ich wirklich Stummel will. Ich dachte, ich würde das oben richtig machen, aber es gibt nicht das Ergebnis, das ich erwarte.

Hier ist meine Helferklasse.

import java.security.cert.X509Certificate 

class X509CertificateUtils { 

    static def prettyPrint(X509Certificate x509Certificate) { 
     return "Subject: ${x509Certificate.getSubjectDN()}" 
    } 
} 

Wenn ich laufen diesen Test ich die folgende Fehlermeldung erhalten:

output == "Subject: Test" 
|  | 
|  false 
|  38 differences (20% similarity) 
|  Subject: (Mock for)t(ype 'Principal' named 'dummy') 
|  Subject: (Tes------)t(-----------------------------) 
Subject: Mock for type 'Principal' named 'dummy' 

Jede Hilfe dankbar empfangen werden würde.

Antwort

6

Erstellen Sie einfach einen zweiten Stummel:

X509Certificate stubCert = Stub() 
Principal princ = Stub() 
princ.toString() >> "Test" 
stubCert.getSubjectDN() >> princ 
+0

Danke dafür. Das hat mein Problem gelöst. Ich bin dieser Lösung ein paar Mal nahe gekommen. Aus Interesse wissen Sie, warum die Verkettung der Methoden nicht funktioniert hat? – Sion

+0

Chaining Stubs gilt als "Code-Geruch", können Sie mehr darüber in dieser verwandten Frage (und erste Antwort) lesen: http://StackOverflow.com/Questions/7926891/Mock-Or-Stub-for-chained-call . Auch ist die aktuelle Implementierung von Stubs in Spock einfach nicht programmiert, Stub-Verkettung zu unterstützen, "a.method() >> b" ist im Grunde ein syntaktischer Zucker, der in etwas wie "Registrieren eines Stubs auf Objekt" eine "für Methode" -Methode übersetzt "zurück" b "'. In Ihrem Fall ruft Spock zuerst 'stubCert.getSubjectDN()' auf, erwartet dann, dass das Ergebnis ein Stub ist und versucht, "toString" für dieses zurückgegebene Objekt zu registrieren. – bezmax

+0

Danke, dass du dir die Zeit genommen hast zu antworten. Sehr geschätzt. – Sion

3

Spock hat ein paar Ansätze zu fälschen Objekte. Hier ist die current documentation.

  • Stub: Eine gefälschte Objekt, das nur zurückgibt, was es erzählt wird; ein Standardwert Wert andernfalls (0, leer, usw.).
  • Mock: Ähnlich einem Stub, aber es kann auch die Anzahl der Methodenaufrufe auf das Objekt testen.
  • Spy: Eine normale Instantiierung Ihres Objekts, die Mocks werden als Listener angewendet, die Aufrufe an das Objekt abfangen. Dadurch können Sie das Objekt normal verwenden, wobei sich nur die angegebenen Methoden ändern. Es ist auch möglich, den ursprünglichen Code zu einem bestimmten Zeitpunkt während Ihres gespotteten Verhaltens aufzurufen.

Meine Frage an Sie ... Versuchen Sie, zu testen, ob Schön() allein richtig funktioniert, dass SubjectDN.toString() druckt richtig, oder eine Kombination aus beidem? Mein Vorschlag ist es, dass Ihr Mock ein tatsächliches SubjectDN() - Objekt zurückgibt, das Sie dann ebenfalls testen. Nicht viel mehr Arbeit, und wenn etwas kaputt geht, haben Sie eine bessere Vorstellung davon, woher das Problem stammt. Die Lösung von Max löst Ihre Frage. Ich habe nicht nahe genug gelesen oder bin guten Test-Scoping-Praktiken gefolgt. Ich überlasse den Rest meiner Antwort als Denkanstoß. Wenn Sie Max 'Stub-Ansatz mit meiner Parametrisierung mischen möchten, würde ich vorschlagen, die gewünschte Zeichenfolge im WHERE-Block an die Stub-Erstellung im Setup-Block zu übergeben.

Dies fängt an Thema zu lösen, aber wenn Sie mehr als ein SubjectDN Szenario (Null, leer, verschiedene Großbuchstaben, Numerik, etc.) testen müssen; Sie sollten auch in die Parametrisierung Ihres Tests schauen.

def "pretty print returns correct string"() { 
    setup: 
     X509Certificate stubCert = Mock() 
     stubCert.getSubjectDN() >> subject 

    expect: 
     subject.toString() == expectedToString 
     X509CertificateUtils.prettyPrint(stubCert) == expectedFormatted 

    where: 
     subject | expectedToString | expectedFormatted 
     new SubjectDN("") | ???? | "Subject: ????" 
     new SubjectDN(null) | ???? | "Subject: ????" 
     new SubjectDN("test") | "test" | "Subject: Test" 
     new SubjectDN("testing") | "testing" | "Subject: Testing" 
} 

Wenn Ihr ziemlich Druck wirklich so einfach, wie das Voranstellen von „Betreff:“ ist, dass Sie wahrscheinlich weg mit der Berechnung Ihrer expectedFormatted Variable bekommen konnte; aber Sie sollten Ihren Test nicht wirklich den Code nachahmen lassen, den Sie testen, um das Testen zu vereinfachen.

Ich finde auch, dass das Tabellenformat der Parametrisierung der Tests unordentlich oder schwierig zu pflegen ist, wenn die Iterationen eine Flüssigkeitslänge haben. Meine Präferenz besteht darin, eine Liste von Karten zu erstellen, wobei jede Karte eine Testiteration darstellt. Es hält jede Test-Iteration gebündelt und gibt unbekannten Entwicklern eine bessere Vorstellung davon, was jede Iteration des Tests mit sich bringt.

@Unroll(iteration.testName) // Shows each iteration in its own result (in most IDEs) 
def "testing printing of a SubjectDN"() { 
    setup: 
     X509Certificate stubCert = Mock() 
     stubCert.getSubjectDN() >> iteration.subject 

    expect: 
     subject.toString() == iteration.expectedToString 
     X509CertificateUtils.prettyPrint(stubCert) == expectedFormatted 

    where: 
     iteration << [ 
      [testName: "Testing pretty printing a normal SubjectDN", 
      subject: new SubjectDN("test"), 
      expectedToString: "test"], 

      [testName: "Testing pretty printing a normal SubjectDN", 
      subject: new SubjectDN("testing 123"), 
      expectedToString: "testing 123"], 

      [testName: "Testing pretty printing a null SubjectDN", 
      subject: new SubjectDN(null), 
      expectedToString: ????] 

      // And so on...    
     ] 

     expectedFormatted = "Subject: ${iteration.expectedToString}" 
} 
+0

Danke für diese Antwort. Ich habe mich aus Gründen der Kürze für Max entschieden, aber ich habe viel von Ihrer Antwort gelernt. :-) – Sion

+0

Danke, dass du mir die Chance gegeben hast, genug Punkte zu verdienen, um einen Kommentar abzugeben! =) – ScientificMethod

Verwandte Themen