Proprietà di stub con i setter privati per i test

8

Abbiamo l'oggetto

public class MyObject{
    protected MyObject(){}

    public string Property1 {get;private set;}
    public string Property2 {get;private set;}
    public string Property3 {get;private set;}
    public string Property4 {get;private set;}
    public string Property5 {get;private set;}
    public string Property6 {get;private set;}
    public string Property7 {get;private set;}
    public string Property8 {get;private set;}
    public string Property9 {get;private set;}
    public string Property10 {get;private set;}
}

Nel nostro codice di produzione popoliamo questo oggetto tramite l'automapper. Può accedere alle proprietà e impostarle correttamente.

Ora, quando vogliamo testare questa classe in una futura pipeline, non è possibile popolare le proprietà con valori fittizi (da testare).

Ci sono alcune opzioni disponibili.

  • Costruttori personalizzati per accettare i parametri richiesti per i test e impostare le proprietà, attualmente sono richiesti 3 costruttori. Questo non è pulito poiché i costruttori non offrono alcuna funzionalità aziendale.

  • Rendi virtuali le proprietà in modo che la classe possa essere cancellata. Ma contrassegnare le proprietà virtuali non fornisce alcun valore aziendale e inquina la mia classe.

  • Aggiungi un costruttore di oggetti alla classe per costruire internamente l'oggetto. Ancora nessun valore commerciale aggiunto. Forse un po 'più pulito ma ancora un sacco di codice non rilevante negli oggetti del dominio.

Qualche suggerimento, consiglio o opzioni alternative qui?

    
posta JMan 09.12.2015 - 14:04
fonte

3 risposte

7

Hai un certo numero di opzioni.

  • Vai avanti e usa costruttori personalizzati, proprietà virtuali o un costruttore di oggetti. La logica alla base di questo è che un oggetto dovrebbe stare da solo e non dipendere da qualche magia come l'automapper. Una classe che è completamente inutile a meno che non ci sia un po 'di magia in corso non è una lezione molto ben pensata. "Il valore aziendale" non è l'unico fattore determinante di un buon design.

  • Include l'automapper nel processo di test. Alcuni diranno che questo non è più un test unitario. Non importa. Il test delle unità non è il tipo di test solo .

  • Implementare qualcosa che fornisca la funzionalità di automapper appositamente per i test. Puoi facilmente scrivere una piccola utility che userà il reflection per popolare il tuo oggetto da un dizionario contenente nomi e valori di proprietà.

Dai anche un'occhiata a questa domanda & answer: Preferiresti rendere le cose private interne / pubbliche per i test, o usare qualche tipo di hack come PrivateObject?

    
risposta data 09.12.2015 - 15:18
fonte
2

Non esito a usare il riflesso per cose come questa nei test.

Non mi piace rendere virtuali le cose per deridere perché cambia il codice per il motivo sbagliato.

Non conosco l'automapper, ma sono d'accordo con @Mike che includerlo nei test può essere una buona idea. Il test dell'unità di distinzione / test di integrazione non è molto interessante. Certo se la suite di test sta diventando grande e lenta dovrai filtrare e classificare le cose per eseguire solo un sottoinsieme sensibile di tutti i test alla frequenza più alta.

Esempio di hack usando il reflection, usando nameof () avresti un risultato migliore ma poi perdi i tipi.

public static class TestExtensions
{
    public static void SetProperty<TSource, TProperty>(
        this TSource source,
        Expression<Func<TSource, TProperty>> prop,
        TProperty value)
    {
        var propertyInfo = (PropertyInfo)((MemberExpression)prop.Body).Member;
        propertyInfo.SetValue(source, value);
    }
}
    
risposta data 16.12.2015 - 00:25
fonte
0

Per scopi di testing unitario, fai uso di framework di simulazione come Microsoft Fakes, TypeMock e JustMock che fornisce supporto per il mocking di membri privati.

Dai anche un'occhiata a Smocks (pacchetti @nuget disponibili). Limitation of Smocks è, non fornirà l'accesso ai membri privati. Ma ha la capacità di deridere i membri statici e non virtuali. Inoltre è disponibile gratuitamente.

Un altro modo più semplice è utilizzare, PrivateObject / PrivateType.

    
risposta data 16.12.2015 - 08:14
fonte

Leggi altre domande sui tag