2010-04-20 8 views
13

Sto provando il progetto simulato/responsabile. Mi sembra di avere problemi per evitare di restituire i mock ai mock nel caso di oggetti che necessitano di un servizio per recuperare altri oggetti.come evitare di restituire mock da un elenco di oggetti fittati

Un esempio potrebbe essere un oggetto che controlla se le fatture del mese scorso sono state pagate. Ha bisogno di un servizio che recuperi un elenco di fatture. Quindi ho bisogno di prendere in giro quel BillRetrievalService nei miei test. Allo stesso tempo ho bisogno di BillRetrievalMock per restituire fatture burlate (dal momento che non voglio che il mio test faccia affidamento sulla correttezza dell'implementazione di Bill).

Il mio disegno è difettoso? C'è un modo migliore per testare questo? O è questo il modo in cui dovrà essere quando si utilizzano oggetti finder (il ritrovamento delle fatture in questo caso)?

nota a margine: anche se Bill potrebbe essere un oggetto candidato valore, il problema più ampio rimane ancora quando le raccolte non contengono oggetti valore (ad esempio utenti).

+0

Si noti che l'ultimo tag era troppo lungo e quindi troncato (e aveva anche un refuso). –

+0

Stai restituendo fatture derisposte o semplicemente matrici? Un servizio che restituisce una lista di stub sembra perfettamente accettabile per me. – Mathias

+0

@Mathias quelli sono mock il mio oggetto ha bisogno del risultato di un metodo (deriso) su di essi. – koen

risposta

11

La maggior parte delle volte, se ho bisogno di una simulazione per restituire un altro finto, trovo una dipendenza che ha più senso nella direzione opposta. Detto in modo diverso, il mock-return-mock di solito indica una violazione del principio di inversione delle dipendenze.

Un'eccezione comune: una fabbrica che crea oggetti (al contrario di un "titolare" che restituisce sempre lo stesso oggetto ogni volta). Se ho bisogno di creare più oggetti dello stesso tipo durante la mia vita, allora potrei aver bisogno di dipendere da uno ObjectFactory e invocare #createObject(), quindi forse impostare le aspettative sugli Oggetti. Anche così, vorrei mettere in discussione questo. Potrebbe essere possibile per qualcos'altro livello uno sopra lo stack di chiamate per creare Object s per me e darli a me, se necessario.

Nel caso ObjectHolder, piuttosto che a seconda della ObjectHolder per ottenere il Object, preferisco dipendere dal Object direttamente e costringere il mio interlocutore a dare a me come vuole. Ciò rispetta la proprietà di progettazione auspicabile dell'indipendenza del contesto .

Una versione specifica di questo problema è il pattern "Orologio virtuale". A volte è necessario dipendere dall'orologio virtuale, ma spesso è meglio semplicemente richiedere un timestamp. (Modello "Richiesta istantanea")

10

I finti mock di ritorno sono un forte odore di codice, un possibile problema con il design. Potrebbe essere che i Bills dovrebbero essere oggetti valori immutabili che non dovrebbero essere derisi. Oppure c'è una certa confusione con il design e le responsabilità delle classi.

Il libro Growing Object-Oriented Software, Guided by Tests e il documento Mock Roles, not Objects dagli inventori di oggetti finti sono da leggere.

+0

Possiedo una copia del libro e ho letto il giornale. Quello che voglio evitare sono i test che non riescono e devo chiedermi se il problema derivi dalla logica di isPaid in the Bills. Gli oggetti di valore non irriverenti sembrano suoni quando sono veramente semplici. – koen

4

Di solito quando mi burlo finisco per avere una triade di oggetti. Il primo oggetto sarebbe un coordinatore BillsPaidLastMonthCoordinator questo oggetto ha due dipendenze BillRetrievalService e BillPaidValidator.

Si deriderebbero le due dipendenze e il test sarebbe per l'interazione di recupero e il passaggio di fatture alla convalida. Quindi per questo test non ti interessa quali siano i dati. Questo aiuta a separare le responsabilità. L'oggetto originale era responsabile del recupero di Bills e quindi della visualizzazione di una fattura di isPaid.

Con il modo in cui hai descritto il problema che puoi finire è un test rumoroso e fragile. La fragilità deriva dal fatto che può essere spezzata in due modi.

Con il corrdinator, non deve essere modificato se le modifiche di implementazione sono Bill, Solo gli oggetti che attualmente utilizzano uno Bill. I miei 2centavos.

[EDIT]

Questo è più allineato con l'utilizzo di gestori di eventi (il coordinatore)

4

quanto Way of the Testuvius consigli, nessun principio, per quanto buona, dovrebbe essere preso assolutamente e così è anche con la regola secondo cui non dovresti aver bisogno di mock che restituiscono mock, ci sono casi in cui questo è abbastanza adatto.

Come suggerisce Gutzofter, è possibile suddividere l'oggetto in due, uno per la convalida effettiva e un altro per il recupero delle fatture da convalidare. Il vantaggio di questa applicazione del principio "unica responsabilità" è che il validatore sarebbe più generico e riutilizzabile. D'altra parte, se si ha solo questo caso d'uso semplice e non c'è bisogno speciale per la maggiore riusabilità, è molto pragmatico mantenere il recupero e la convalida in una singola classe. La stratificazione, l'esplosione del numero di oggetti ecc. Ingiustificati da un bisogno reale e da un beneficio reale, fatti solo per soddisfare un principio astratto, non sono buoni.Devi sempre pesare i pro ei contro e la realtà raramente è semplice e bella come vorremmo :-) Grandi esempi di questo approccio pragmatico sono nei modelli Real World Java EE di Adam Bien - Rethinking Best Practices.

Problemi correlati