Domanda

In una recente domanda sullo stub, molte risposte hanno suggerito interfacce o delegati C# per l'implementazione di stub, ma una risposta suggerito di utilizzare la compilazione condizionale, mantenendo l'associazione statica nel codice di produzione.Questa risposta è stata modificata -2 al momento della lettura, quindi almeno 2 persone pensavano davvero che fosse una sbagliato risposta.Forse la ragione è stato l'uso improprio di DEBUG, o forse l'uso di un valore fisso invece di una convalida più ampia.Ma non posso fare a meno di chiedermi:

L'uso della compilazione condizionale è una tecnica inappropriata per implementare stub di test unitari?A volte?Sempre?

Grazie.

Modifica-aggiungi: Vorrei aggiungere un esempio come esperimento impegnativo:

class Foo {
    public Foo() { .. }
    private DateTime Now { 
      get {
#if UNITTEST_Foo
        return Stub_DateTime.Now;
#else
        return DateTime.Now;
#endif
      }
    }
    // .. rest of Foo members
}

rispetto a

interface IDateTimeStrategy { 
    DateTime Now { get; }
}
class ProductionDateTimeStrategy : IDateTimeStrategy {
  public DateTime Now { get { return DateTime.Now; } }
}
class Foo {
    public Foo() : Foo(new ProductionDateTimeStrategy()) {}
    public Foo(IDateTimeStrategy s) { datetimeStrategy = s; .. }
    private IDateTime_Strategy datetimeStrategy;
    private DateTime Now { get { return datetimeStrategy.Now; } }
}

Ciò consente di interrompere la dipendenza in uscita da "DateTime.Now" tramite un'interfaccia C#.Tuttavia, ora abbiamo aggiunto una chiamata di invio dinamica dove sarebbe sufficiente la chiamata statica, l'oggetto è più grande anche nella versione di produzione e abbiamo aggiunto un nuovo percorso di errore per il costruttore di Foo (l'allocazione può fallire).

Mi sto preoccupando per niente qui?Grazie per il feedback finora!

È stato utile?

Soluzione

Cerca di mantenere il codice di produzione separato dal codice di test.Mantenere diverse gerarchie di cartelle.diverse soluzioni/progetti.

Salvo che..sei nel mondo del codice C++ legacy.Qui va bene tutto..se i blocchi condizionali ti aiutano a rendere parte del codice testabile e vedi un vantaggio..Fallo assolutamente.Ma cerca di non lasciare che diventi più confuso dello stato iniziale.Commenta e delimita chiaramente i blocchi condizionali.Procedi con cautela.È una tecnica valida per ottenere codice legacy sotto un test cablaggio.

Altri suggerimenti

Penso che riduca la chiarezza per le persone che rivedono il codice.Non dovresti ricordare che esiste un tag condizionale attorno al codice specifico per comprendere il contesto.

No, è terribile.Perde test nel codice di produzione (anche se è condizionato)

Male male.

Il codice di test dovrebbe essere ovvio e non mescolato negli stessi blocchi del codice testato.

Questo è più o meno lo stesso motivo per cui non dovresti scrivere

if (globals.isTest)

Ho pensato a un altro motivo per cui era terribile:

Molte volte deridi/stub qualcosa, vuoi che i suoi metodi restituiscano risultati diversi a seconda di ciò che stai testando.Questo o lo preclude o lo rende imbarazzante da morire.

Potrebbe essere utile come strumento su cui appoggiarsi durante il refactoring per la testabilità in una base di codice di grandi dimensioni.Posso vedere come potresti utilizzare tali tecniche per abilitare modifiche più piccole ed evitare un refactoring "big bang".Tuttavia mi preoccuperei di appoggiarmi troppo a una tecnica del genere e proverei a garantire che tali trucchi non vivano troppo a lungo nella base di codice, altrimenti rischi di rendere il codice dell'applicazione molto complesso e difficile da seguire.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top