2013-01-08 2 views
6

Ich versuche, private Methoden in einem Unit-Test-Projekt zu testen. Bis jetzt läuft es super, aber ich stoße auf eine Beule, wenn ich eine Methode mit einem Out-Parameter testen muss. Die Signatur für diese Methode ist:PrivateObject nicht Parameter

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

Und der Unittest (der Teil, der nicht funktioniert) sieht wie folgt aus:

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); 

Die GotSSI Methode arbeiten. Ich habe es im Debug-Modus innerhalb des Komponententests getestet und ich kann sehen, dass die Variable 'ssi' out in der Methode gesetzt ist, bevor sie den Wert 'wahr' oder 'falsch' zurückgibt. Wenn der Test jedoch zu seinem eigenen Code zurückkehrt, ist die Variable 'ssi' immer noch null. Das Problem ist also, dass das Objekt, das ich in der "GotSSI" -Methode erstellt habe, nicht aus der PrivateObject-Aufrufmethode herausgefiltert wird.

Wer weiß, was ich vermisse?

Update (Lösung von Rafal)

Rafal-Lösung perfekt funktionieren und hier ist, wie ich die Lösung implementiert.

hat ich einen Delegierten:

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

Und wenn ich das Objekt erstellt habe ich testen wollte, baue ich die Delegaten (Soll das Objekt i Testen bin):

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

Danach ist es sehr einfach, den Delegierten zu rufen:

Die Lösung ist sehr einfach und funktioniert wie ein Charme.

+0

könnte Sinn machen, eine Hilfsklasse zu definieren, für die Herstellung diese für Sie: interne statische T MakeDelegate (string method, T Ziel) {return (T) Delegate.CreateDelegate (typeof (T), Ziel, typeof (C) .GetMethod (Methodenname, BindingFlags.NonPublic | BindingFlags.Instance));} Aber vielleicht hast du schon darüber nachgedacht. :-) – JLRishe

+0

Nicht wirklich. Es war nur ein Test, der dieses Problem hatte, und ich war unter Zeitdruck. Trotzdem eine gute Idee. – evilfish

Antwort

3

Ihr Aufruf der Methode mit out-Parameter ist falsch, wenn Sie den out-Wert erhalten möchten. Siehe this, um es mit Reflektion aufzurufen.

0

Sie müssen sich fragen, ob Sie wirklich private Methoden testen müssen? Ich persönlich prüfe nicht Private Methoden, aber es ist alles auf persönliche Meinung (und es kann ziemlich heiß werden). Es gibt zahlreiche Gründe/Artikel/Meinungen. A good SO thread can be found here.

Ein Auszug aus der akzeptierten Antwort ist „Eine private Methode ist eine Implementierung Detail, die die Benutzer der Klasse ausgeblendet werden soll. Testing private Methoden Kapselung brechen ...

Der Grund, warum ich nicht tun Testen Sie meine privaten Methoden, weil sie sich eher ändern als die öffentliche Schnittstelle. Wenn Sie alle Ihre privaten Methoden abdecken, macht das Refactoring komplexer (wieder, nur meine Meinung). Wenn Sie eine private Methode ändern und die öffentliche Schnittstelle bricht, wissen Sie, dass die Tests Ihrer Einheit fehlschlagen und Sie können dann einen Drilldown durchführen.

Das ist nur meine Meinung und ich weiß, dass viele nicht zustimmen, also einfach es da draußen!

+0

Ich bin mir der generellen Übereinstimmung gegenüber der Unit-Test-Methode bewusst, und normalerweise tue ich es nicht. Problem hier ist, dass diese Methoden, die ich teste, von der öffentlichen Methode, die ich verwenden könnte, komplex einzurichten ist. Die Verwendung privater Tests ist viel einfacher zu kontrollieren und zu verstehen. – evilfish

+1

Neugierig wer/warum die down-vote? Sie haben das Recht, nach unten zu stimmen, aber es hilft, WARUM zu kommentieren, sonst scheint es ziemlich sinnlos. – Belogix

4

Obwohl die endgültige Lösung, die akzeptiert wurde, funktioniert, gibt es einen viel einfacheren Weg, dies zu tun. Wenn Sie dem Link in der Antwort von Rafal folgen, finden Sie eine ähnliche Frage mit zwei Antworten. Die zweite Antwort (mit den "nützlichsten" Punkten) ist die einfachere der beiden.Hier

ist eine modifizierte Version dieser Antwort speziell für ein Testszenario:

//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

Ich habe es versucht und richtig gearbeitet. Vielen Dank. – mggSoft