2013-01-08 9 views
6

Próbuję przetestować prywatne metody w projekcie testu jednostkowego. Do tej pory wszystko idzie świetnie, ale trafiłem w guz, kiedy muszę przetestować metodę z parametrem out. Podpis dla tej metody jest:PrivateObject nie powróci parametr

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

A unittest (część, która nie pracuje) wygląda następująco:

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

Prace metoda GotSSI. Przetestowałem go w trybie debugowania w ramach testu urządzenia i widzę, że zmienna 'ssi' jest ustawiana wewnątrz metody, przed zwróceniem jej wartości true lub false. Ale kiedy test powraca do swojego własnego kodu, zmienna "ssi" jest nadal pusta. Problem polega na tym, że obiekt, który utworzyłem w metodzie "GotSSI", nie jest przetwarzany z metody wywołania PrivateObject.

Ktoś wie, czego mi brakuje?

Update (Rozwiązanie przez Rafal)

praca rozwiązanie Rafała doskonale i oto jak I wdrożone rozwiązanie.

stworzyłem Delegat:

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

I kiedy stworzyliśmy obiekt chciałem przetestować, zbudować delegata (cel jest przedmiotem Jestem testowania):

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

Po tym jest bardzo łatwo zadzwonić do delegata:

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

Rozwiązanie jest bardzo proste i działa jak urok.

+0

może mieć sens, aby zdefiniować klasę pomocniczą dla dokonywania tych dla Ciebie: wewnętrzny statyczny T MakeDelegate (string methodName, cel T) {return (T) Delegat.CreateDelegate (typeof (T), target, typeof (C) .GetMethod (methodName, BindingFlags.NonPublic | BindingFlags.Instance));} Ale może już o tym pomyślałeś. :-) – JLRishe

+0

Niezupełnie. To był tylko jeden test, który miał ten problem, a także byłem pod presją czasu. Dobry pomysł, nie mniej. – evilfish

Odpowiedz

3

Twoje wywołanie metody z parametrem out jest nieprawidłowe, jeśli chcesz uzyskać wartość out. Zobacz this, jak go wywołać z refleksją.

0

Musisz zadać sobie pytanie, czy naprawdę musisz przetestować prywatne metody? Osobiście nie testuję prywatnych metod, ale wszystko sprowadza się do osobistej opinii (i może być dość gorąca). Istnieje wiele powodów/artykułów/opinii. A good SO thread can be found here.

Fragment przyjętego odpowiedź brzmi „Sposób prywatny jest szczegółów wdrażania, które powinny być ukryte dla użytkowników klasy. Metody badania prywatne przerywa hermetyzacji ...

Powodem nie wiem przetestuj moje prywatne metody, ponieważ są bardziej skłonne do zmiany niż publiczny interfejs. Jeśli obejmiesz wszystkie prywatne metody, to sprawisz, że refaktoryzacja będzie bardziej złożona (znowu, tylko moja opinia). Jeśli zmienisz metodę prywatną i przerwy w interfejsie publicznym, będziesz wiedział, że testy jednostek zakończą się niepowodzeniem, a następnie możesz drążyć.

To tylko moja opinia i wiem, że wielu się nie zgadza, więc po prostu go stawiaj!

+0

Jestem świadomy ogólnego konsensusu wobec metody testowania prywatnej jednostki i zwykle tego nie robię. Problem polega na tym, że te metody, które testuję, są skomplikowane, ponieważ można je skonfigurować z wykorzystaniem publicznej metody, której mogłem użyć. Korzystanie z prywatnych testów jest łatwiejsze do kontrolowania i zrozumienia. – evilfish

+1

Ciekawy, kto/dlaczego głosowanie w dół? Masz prawo do głosowania na niższy poziom, ale pomaga ci skomentować DLACZEGO, w przeciwnym razie wydaje się to dość bezsensowne. – Belogix

4

Chociaż ostateczne rozwiązanie, które zostało zaakceptowane, działa znacznie prostiej. Jeśli podążysz za linkiem podanym w zaakceptowanej odpowiedzi Rafała, znajdziesz podobne pytanie do tego, z dwiema odpowiedziami. Druga odpowiedź (z najbardziej "użytecznymi" punktami) jest prostsza z dwóch.

Oto zmodyfikowana wersja tej odpowiedzi specjalnie dla scenariusza testowania:

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

Wypróbowałem i działałem poprawnie. Dzięki. – mggSoft

Powiązane problemy