Mocking introduce la gestione nel codice di produzione

15

Supponendo un'interfaccia IReader, un'implementazione dell'interfaccia IReader ReaderImplementation e una classe ReaderConsumer che consuma ed elabora i dati dal lettore.

public interface IReader
{
     object Read()
}

Attuazione

public class ReaderImplementation
{
    ...
    public object Read()
    {
        ...
    }
}

Consumer:

public class ReaderConsumer()
{
    public string location

    // constructor
    public ReaderConsumer()
    {
        ...
    }

    // read some data
    public object ReadData()
    {
        IReader reader = new ReaderImplementation(this.location)
        data = reader.Read()
        ...
        return processedData    
    }
}

Per testare ReaderConsumer e l'elaborazione, utilizzo una simulazione di IReader. Quindi ReaderConsumer diventa:

public class ReaderConsumer()
{
    private IReader reader = null

    public string location

    // constructor
    public ReaderConsumer()
    {
        ...
    }

    // mock constructor
    public ReaderConsumer(IReader reader)
    {
        this.reader = reader
    }

    // read some data
    public object ReadData()
    {
        try
        {
            if(this.reader == null)
            {
                 this.reader = new ReaderImplementation(this.location)
            }

            data = reader.Read()
            ...
            return processedData    
        }
        finally
        {
            this.reader = null
        }
    }
}

In questa soluzione, il mocking introduce una frase if per il codice di produzione, poiché solo il costruttore mocking fornisce un'istanza dell'interfaccia.

Durante la scrittura, mi rendo conto che il blocco try-finally è in qualche modo non correlato poiché è lì per gestire l'utente che cambia la posizione durante l'esecuzione dell'applicazione.

Nel complesso sembra maleodorante, come potrebbe essere gestito meglio?

    
posta kristian mo 23.01.2017 - 10:58
fonte

3 risposte

67

Invece di inizializzare il lettore con il tuo metodo, sposta questa linea

{
    this.reader = new ReaderImplementation(this.location)
}

Nel costruttore parametrico predefinito.

public ReaderConsumer()
{
    this.reader = new ReaderImplementation(this.location)
}

public ReaderConsumer(IReader reader)
{
    this.reader = reader
}

Non esiste un "mock constructor", se la tua classe ha una dipendenza che richiede per funzionare, allora il costruttore dovrebbe o fornire quella cosa o crearla.

    
risposta data 23.01.2017 - 11:25
fonte
54

Hai solo bisogno del singolo costruttore:

public class ReaderConsumer()
{
    private IReader reader = null

    public string location

    // constructor
    public ReaderConsumer(IReader reader)
    {
        this.reader = reader;
    }

nel codice di produzione:

var rc = new ReaderConsumer(new ReaderImplementation(0));

nel tuo test:

var rc = new ReaderConsumer(new MockImplementation(0));
    
risposta data 23.01.2017 - 11:12
fonte
13

Esamina Iniezione delle dipendenze e Inversione del controllo

Sia Ewan che RubberDuck hanno risposte eccellenti. Ma volevo menzionare un'altra area in cui esaminare Dependency Injection (DI) e Inversion of Control (IoC). Entrambi questi approcci spostano il problema che stai riscontrando in un framework / libreria in modo da non doverti preoccupare.

Il tuo esempio è semplice e viene rapidamente eliminato, ma inevitabilmente lo svilupperai e ti ritroverai con tonnellate di costruttori o routine di inizializzazione che assomigliano a:

var foo = new Foo (nuova barra (nuova Baz (), nuova Quz ()), nuova Foo2 ());

Con DI / IoC utilizzi una libreria che ti consente di definire le regole per l'abbinamento delle interfacce alle implementazioni e poi dici "Give me a Foo" e funziona come collegare tutto.

Ci sono molti contenitori IoC molto amichevoli (come vengono chiamati) là fuori, e ho intenzione di raccomandarne uno da guardare, ma, per favore, esplora, dato che ci sono molte scelte eccellenti.

Uno semplice da iniziare è:

link

Ecco un elenco da esplorare:

link

    
risposta data 23.01.2017 - 14:36
fonte

Leggi altre domande sui tag