Unità-Test delle funzioni che hanno parametri di classi in cui il codice sorgente non è accessibile

2

In relazione a questa domanda , Ho un'altra domanda riguardante le funzioni di test delle unità nelle classi di utilità:

Supponi di avere firme di funzioni come questa:

public function void doSomething(InternalClass obj, InternalElement element)

dove InternalClass e InternalElement sono entrambe Classi il cui codice sorgente non è disponibile, poiché sono nascosti nell'API. Inoltre, doSomething funziona solo su oggetti ed elementi. Ho pensato di prendere in giro quelle lezioni, ma questa opzione non è possibile a causa del fatto che non implementano affatto un'interfaccia che potrei usare per le mie classi di Mocking.

Tuttavia, ho bisogno di compilare obj con dati definiti per testare DoSomething.

In che modo questo problema può essere risolto?

    
posta McMannus 18.06.2013 - 12:16
fonte

4 risposte

5

Quello che stai cercando è il modello dell'adattatore: link

Usando questo modello puoi creare un wrapper attorno alla classe esterna.

Consente di prendere la seguente classe esterna:

public sealed class SomeExternalClassWithoutInterface
{
    private readonly string _someValue;

    public SomeExternalClassWithoutInterface(string someConstructorValue)
    {
        _someValue = someConstructorValue;
    }
    public string Method1()
    {
        return _someValue;
    }

    public int Method2()
    {
        return _someValue.Length;
    }
}

Ora possiamo facilmente creare la nostra classe come wrapper attorno a questa classe esterna e Implementare un'interfaccia:

public class ExternalClassAdapter : IExternalClassAdapter
{
private readonly SomeExternalClassWithoutInterface _someExternalClassWithoutInterface;

// DI implementation, this is not neccesary
public ExternalClassAdapter(SomeExternalClassWithoutInterface someExternalClassWithoutInterface)
{
    _someExternalClassWithoutInterface = someExternalClassWithoutInterface;
}

// Constructor Without Depedency Injection, this is not preferable.
public ExternalClassAdapter(string someValue)
{
   _someExternalClassWithoutInterface = new SomeExternalClassWithoutInterface(someValue);
}

public string Method1()
{
    return _someExternalClassWithoutInterface.Method1();
}

public int Method2()
{
    return _someExternalClassWithoutInterface.Method2();
}

}

Questa è la nostra interfaccia, che sta implementando tutti i metodi usati nella classe esterna. (Se sono disponibili molti metodi, separare le interfacce in base al principio di Segregazione interfaccia)

public interface IExternalClassAdapter
    {
        string Method1();
        int Method2();
    }

Ora, quando questa classe Adapter viene utilizzata nell'applicazione anziché nella classe esterna, dovresti essere in grado di prendere in giro qualsiasi altra implementazione abbastanza facilmente.

Non dovresti mai usare classi esterne non interfacciate nel tuo codice.

Link di Pastebin (poiché la descrizione del codice non funziona bene qui): link

Se, per qualsiasi motivo, hai bisogno anche di un modello di facciata ... Puoi ancora avvolgere questi 2 adattatori in una singola facciata! Ma non creare un'unica facciata su 2 classi esterne!

    
risposta data 25.06.2013 - 09:26
fonte
5

Se non è troppo tardi per modificare un po 'del tuo codice potresti avvolgere InternalClass e InternalElement e fornire un'interfaccia per il wrapper in modo che l'oggetto spostato possa essere facilmente deriso (essenzialmente pattern di adattamento ).

Se non controlli queste classi è probabilmente una buona idea avvolgerle comunque per isolare le modifiche in esse dal tuo codice.

    
risposta data 18.06.2013 - 14:19
fonte
-1

Probabilmente hai già provato questa opzione, ma non lo specifichi espressamente nella tua domanda:

È possibile creare un'istanza degli oggetti e impostarli su un determinato stato? Forse chiamare doSomething produce un nuovo stato sufficiente a verificare che funzioni correttamente sugli oggetti?

Naturalmente se uno degli oggetti lancia un missile nucleare tocca molto stato esterno, potrebbe essere un no-no.

    
risposta data 19.06.2013 - 02:10
fonte
-1

Ecco un trucco che a volte funziona in casi del genere: nel tuo gruppo di test, non fare riferimento all'assieme contenente doSomething . Invece, fai riferimento al file del codice sorgente che contiene doSomething e fornisci la tua implementazione InternalClass / InternalElement (che funge da simulazione) in quell'assembly di test. Naturalmente, InternalClass deve esporre esattamente le stesse firme del metodo pubblico di quella originale, almeno nella misura in cui è possibile compilare il codice di prova. Dovrebbe essere ovvio che devi anche usare lo stesso spazio dei nomi della classe originale.

Ho usato questa tecnica con successo per testare il codice legacy anche se avevo il codice sorgente disponibile, ma non volevo toccarlo.

    
risposta data 18.06.2013 - 12:32
fonte

Leggi altre domande sui tag