2015-09-07 27 views
5

devo cominciare scusandomi se i termini che uso non sono corretti. Uso groovy/java solo per le attività di automazione (Gradle) e non ho anni di esperienza nella fornitura di software di qualità produttiva.Spock - valore restituendo fisso non funziona come previsto

Quindi, la mia sfida è la seguente: Ho una specifica che sta provando a testare una stringa di restituzione come previsto (quasi identica a 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" 
} 

Tuttavia, la differenza è che il mio metodo restituisce un oggetto vincolo principale, e la sua toString di quell'oggetto() che ho molta voglia di stub. Ho pensato che lo stavo facendo correttamente sopra, ma non dà il risultato che mi aspetto.

Ecco la mia classe di supporto.

import java.security.cert.X509Certificate 

class X509CertificateUtils { 

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

Se corro questo test ottengo il seguente errore:

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' 

Qualsiasi aiuto sarebbe stato ricevuto con gratitudine.

risposta

6

Basta creare un secondo stub:

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

Grazie per questo. Questo ha risolto il mio problema. Mi sono avvicinato a questa soluzione alcune volte. Per curiosità sai perché concatenare i metodi non ha funzionato? – Sion

+0

Gli stub concatenati sono considerati un "odore di codice", puoi leggere ulteriori informazioni in merito a questa domanda correlata (e prima risposta): http://stackoverflow.com/questions/7926891/mock-or-stub-for-chained-call . Inoltre, l'attuale implementazione di Stubs in Spock non è semplicemente programmata per supportare il concatenamento dello stub, 'a.method() >> b' è fondamentalmente uno zucchero sintattico che si traduce in qualcosa come" register a stub on object "a" for method "method "per restituire" b "'. Nel tuo caso, Spock prima chiama 'stubCert.getSubjectDN()', quindi si aspetta che il risultato sia uno Stub e prova a registrare "toString" su questo oggetto restituito. – bezmax

+0

Grazie per aver trovato il tempo di rispondere. Molto apprezzato. – Sion

3

Spock ha un paio di approcci alla oggetti fingendo. Ecco lo current documentation.

  • Stub: Un oggetto falso che restituisce solo ciò che viene detto di; un valore predefinito altrimenti (0, vuoto, ecc.).
  • Mock: simile a uno stub, ma è in grado di verificare il numero di chiamate di metodo effettuate sull'oggetto.
  • Spy: Un normale esemplificazione del vostro oggetto, i mock vengono applicate come ascoltatori che le chiamate intercettare all'oggetto. Ciò consente di utilizzare normalmente l'oggetto, cambiando solo i comportamenti dei metodi specificati. È anche possibile chiamare il codice originale ad un certo punto durante il tuo comportamento beffardo.

La mia domanda per voi ... Si sta tentando di provare che prettyPrint() da solo funziona correttamente, che SubjectDN.toString() stampe correttamente, o una combinazione dei due? Il mio suggerimento è di fare in modo che il tuo mock restituisca un oggetto SubjectDN() reale che poi testerai. Non c'è molto più lavoro, e se qualcosa si rompe hai un'idea migliore di dove è nato il problema. La soluzione di Max risolverà la tua domanda; Non ho letto abbastanza da vicino o seguo buone pratiche di scoping del test. Lascerò il resto della mia risposta come spunto di riflessione. Se si desidera mixare l'approccio di stub di Max con la mia parametrizzazione, suggerirei di passare la stringa desiderata nel blocco where alla creazione dello stub nel blocco di installazione.

Questo sta cominciando a ottenere fuori tema, ma se avete bisogno di testare più di uno scenario subjectDN (nulli, vuoti, varie capitalizzazioni, numerici, ecc); dovresti esaminare anche la parametrizzazione del test.

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" 
} 

Se la stampa piuttosto è davvero così semplice come anteponendo "Oggetto:" probabilmente si potrebbe ottenere via con il calcolo la variabile expectedFormatted; ma non dovresti fare in modo che il tuo test simuli il codice che stai testando nel tentativo di rendere più semplice il test.

Inoltre, trovo che il formato tabella di parametrizzazione dei test diventa disordinato o difficile da mantenere quando le iterazioni hanno una lunghezza fluida. La mia preferenza è fare una lista di mappe, con ogni mappa che rappresenta una iterazione di prova. Mantiene insieme ogni iterazione di test e offre agli sviluppatori non esperti un'idea migliore di ciascuna iterazione del test.

@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

Grazie per questa risposta. Ho optato per la soluzione di Max per brevità, ma ho imparato molto dalla tua risposta. :-) – Sion

+0

Grazie per avermi dato la possibilità di guadagnare abbastanza punti per commentare! =) – ScientificMethod