2013-01-08 19 views
6

Sto provando a testare i metodi privati ​​in un progetto di test delle unità. Finora sta andando alla grande, ma ho colpito un urto, quando devo testare un metodo con un parametro out. La firma di tale metodo è:PrivateObject non restituisce il parametro

private bool GotSSI(out SSI ssi, RSI rsi) 
{ 
     ~code omitted~ 
} 

E l'unittest (la parte che non funziona) si presenta così:

SSI ssi = null; 
object[] p = new object[]{ssi,rsi}; 
Type[] t = new Type[] { typeof(SSI).MakeByRefType(), typeof(RSI) }; 
actual = (bool) privateTarget.Invoke("GotSSI",t,p); 

Il metodo di lavoro GotSSI. L'ho testato in modalità di debug all'interno del test dell'unità e posso vedere che la variabile 'ssi' out è impostata all'interno del metodo, prima di restituire il valore vero o falso. Ma quando il test ritorna al proprio codice, la variabile 'ssi' è ancora nullo. Quindi il problema è che l'oggetto che ho creato nel metodo "GotSSI" non viene analizzato dal metodo di richiamo di PrivateObject.

Qualcuno sa cosa mi manca?

Update (soluzione da Rafal)

lavoro soluzione di Rafal perfettamente ed ecco come ho implementato la soluzione.

ho creato un delegato:

delegate bool GotSSIInternal(out SSI ssi, RSI rsi); 

E quando ho creato l'oggetto ho voluto mettere alla prova, ho costruire il delegato (la destinazione è l'oggetto sto testando):

GotSSIInternal gotSSIInternal = (GotSSIInternal) Delegate.CreateDelegate(
      typeof (GotSSIInternal), 
      target, 
      typeof(OfflineResolver).GetMethod("GotSSI", BindingFlags.NonPublic | BindingFlags.Instance)); 

Dopo questo è molto semplice chiamare il delegato:

actual = gotSSIInternal.Invoke(out ssi, rsi); 

La soluzione è molto semplice e funziona come un fascino.

+0

potrebbe avere senso per definire una classe di supporto per fare questi per voi: statico T interna MakeDelegate (stringa methodName, bersaglio T) {return (T) Delegate.CreateDelegate (typeof (T), target, typeof (C) .GetMethod (methodName, BindingFlags.NonPublic | BindingFlags.Instance))} Ma forse ci hai già pensato. :-) – JLRishe

+0

Non proprio. Era solo un test che ha avuto questo problema, in più ero sotto la pressione del tempo. Una buona idea non di meno. – evilfish

risposta

3

l'invocazione del metodo con parametro out è errata se si desidera ottenere il valore out. Vedere this su come richiamarlo con la riflessione.

0

È necessario chiedersi se è davvero necessario testare i metodi privati? Io personalmente non testare i metodi privati, ma è tutto merito dell'opinione personale (e può diventare piuttosto caldo). Ci sono numerose ragioni/articoli/opinioni. A good SO thread can be found here.

Un estratto la risposta accettata è "Un metodo privato è un dettaglio di implementazione che dovrebbe essere nascosto agli utenti della classe. Metodi privati ​​di prova rompe l'incapsulamento ..."

Il motivo per cui non lo faccio testare i miei metodi privati ​​è perché sono più propensi a cambiare rispetto all'interfaccia pubblica. Se copri tutti i tuoi metodi privati, rende il refactoring più complesso (di nuovo, solo la mia opinione). Se modifichi un metodo privato e le interruzioni dell'interfaccia pubblica saprai che i test dell'unità falliscono e puoi eseguire il drill down.

Questa è solo la mia opinione e so che molti non sono d'accordo quindi basta metterlo là fuori!

+0

Sono a conoscenza del consenso generale sul metodo privato di test unitario e normalmente non lo faccio. Il problema qui è che questi metodi che sto testando sono complessi da configurare dal metodo pubblico che potrei usare. L'utilizzo di test privati ​​è molto più facile da controllare e capire. – evilfish

+1

Curioso chi/perché il down-vote? Hai diritto al down-vote ma aiuta a commentare PERCHÉ, altrimenti sembra abbastanza inutile. – Belogix

4

Sebbene la soluzione finale accettata funzioni, c'è un modo molto più semplice per farlo. Se segui il link indicato nella risposta accettata di Rafal, troverai una domanda simile a questa, con due risposte. La seconda risposta (con i punti più "utili") è la più semplice delle due.

Ecco una versione modificata di quella risposta specificamente per uno scenario di test:

//method to test is a private method of the class ClassTotest with signature 
// TryGetCustomerData(List<Invoice> invoices, out CustomerData customerData) 
//set up 
var objToTest = new ClassToTest(); 
var invoices = GetInvoices(); 
CustomerData customerData = null; 

//set up the arguments 
var args = new object[] { invoices, customerData }; 
//get the MethodInfo of the method you want to test 
var method = typeof(ClassToTest).GetMethod("TryGetCustomerData", 
    BindingFlags.NonPublic | BindingFlags.Instance); 
//invoke it 
var success = (bool)method.Invoke(objToTest, args); 
//get back the customerData argument - the "out" parameter 
var actual = args[1] as CustomerData; 
+0

L'ho provato e ho funzionato correttamente. Grazie. – mggSoft

Problemi correlati