Visual Studio umożliwia testowanie jednostkowe metod prywatnych za pomocą automatycznie generowanej klasy akcesorium. Napisałem test prywatnej metody, która kompiluje się pomyślnie, ale kończy się niepowodzeniem w czasie wykonywania. Dość minimalna wersja kodu i testu to:
//in project MyProj
class TypeA
{
private List<TypeB> myList = new List<TypeB>();
private class TypeB
{
public TypeB()
{
}
}
public TypeA()
{
}
private void MyFunc()
{
//processing of myList that changes state of instance
}
}
//in project TestMyProj
public void MyFuncTest()
{
TypeA_Accessor target = new TypeA_Accessor();
//following line is the one that throws exception
target.myList.Add(new TypeA_Accessor.TypeB());
target.MyFunc();
//check changed state of target
}
Błąd środowiska wykonawczego to:
Object of type System.Collections.Generic.List`1[MyProj.TypeA.TypeA_Accessor+TypeB]' cannot be converted to type 'System.Collections.Generic.List`1[MyProj.TypeA.TypeA+TypeB]'.
Zgodnie z intellisense - i stąd sądzę, że kompilator - cel jest typu TypeA_Accessor. Ale w środowisku wykonawczym jest typu TypeA, a zatem dodawanie listy kończy się niepowodzeniem.
Czy jest jakiś sposób, aby zatrzymać ten błąd? Lub, być może bardziej prawdopodobne, jakie inne porady mają inne osoby (przewiduję, że „nie testuj metod prywatnych” i „nie testuj jednostkowo testów stanu obiektów”).
c#
unit-testing
Junichiro
źródło
źródło
Odpowiedzi:
Tak, nie testuj prywatnych metod .... Ideą testu jednostkowego jest przetestowanie urządzenia za pomocą jego publicznego „API”.
Jeśli zauważysz, że musisz przetestować wiele prywatnych zachowań, najprawdopodobniej masz nową „klasę” ukrytą w klasie, którą próbujesz przetestować, wypakuj ją i przetestuj za pomocą publicznego interfejsu.
Jedna rada / narzędzie do myślenia ... Istnieje pomysł, że żadna metoda nigdy nie powinna być prywatna. Oznacza to, że wszystkie metody powinny znajdować się na publicznym interfejsie obiektu .... jeśli uważasz, że musisz ustawić go jako prywatny, najprawdopodobniej żyje on na innym obiekcie.
Ta rada nie sprawdza się w praktyce, ale w większości jest dobrą radą i często zmusza ludzi do rozkładania przedmiotów na mniejsze.
źródło
Możesz użyć klasy PrivateObject
źródło
„Nic nie jest nazywane standardową lub najlepszą praktyką, prawdopodobnie są to tylko popularne opinie”.
To samo dotyczy również tej dyskusji.
Wszystko zależy od tego, co uważasz za jednostkę, jeśli uważasz, że UNIT jest klasą, trafisz tylko na metodę publiczną. Jeśli uważasz, że UNIT to linie kodu, uderzanie w prywatne metody nie spowoduje, że poczujesz się winny.
Jeśli chcesz wywołać metody prywatne, możesz użyć klasy „PrivateObject” i wywołać metodę invoke. Możesz obejrzeć ten szczegółowy film na youtube ( http://www.youtube.com/watch?v=Vq6Gcs9LrPQ ), który pokazuje, jak używać „PrivateObject”, a także omawia, czy testowanie metod prywatnych jest logiczne.
źródło
Inną myślą tutaj jest rozszerzenie testów na „wewnętrzne” klasy / metody, dając więcej białych wrażeń na temat tych testów. Możesz użyć InternalsVisibleToAttribute na zestawie, aby udostępnić je osobnym modułom testującym jednostki.
W połączeniu z zapieczętowaną klasą możesz podejść do takiego enkapsulacji, że metoda testowa jest widoczna tylko z najcichszego zestawu twoich metod. Weź pod uwagę, że chroniona metoda w zamkniętej klasie jest de facto prywatna.
I test jednostkowy:
źródło
Jednym ze sposobów testowania metod prywatnych jest refleksja. Dotyczy to także NUnit i XUnit:
źródło
call methods
statyczne i niestatyczne ?Eee ... Przyszedł tutaj z dokładnie tym samym problemem: przetestuj prostą , ale kluczową metodę prywatną . Po przeczytaniu tego wątku wydaje się, że „chcę wywiercić ten prosty otwór w tym prostym kawałku metalu i chcę się upewnić, że jakość odpowiada specyfikacjom”, a potem pojawia się „OK, to nie jest łatwe. Po pierwsze, nie ma do tego odpowiedniego narzędzia, ale możesz zbudować obserwatorium fal grawitacyjnych w swoim ogrodzie. Przeczytaj mój artykuł na stronie http://foobar.brigther-than-einstein.org/ Po pierwsze, oczywiście muszę wziąć udział w niektórych zaawansowanych kursach fizyki kwantowej, wtedy potrzebujesz ton ultra-cool nitrogenium, a następnie, oczywiście, moja książka dostępna w Amazon „...
Innymi słowy...
Nie, najpierw najważniejsze.
Każda metoda, prywatna, wewnętrzna, chroniona, publiczna musi być testowalna. Musi istnieć sposób na wdrożenie takich testów bez takich ceregieli, jak tutaj przedstawiono.
Dlaczego? Właśnie ze względu na wzmianki o architekturze poczynione do tej pory przez niektórych autorów. Być może proste powtórzenie zasad oprogramowania może wyjaśnić pewne nieporozumienia.
W tym przypadku zwykłymi podejrzanymi są: OCP, SRP i, jak zawsze, KIS.
Ale chwileczkę. Pomysł, aby udostępnić wszystko publicznie, jest mniej polityczny i stanowi rodzaj postawy. Ale. Jeśli chodzi o kod, nawet w ówczesnej społeczności Open Source, to nie jest dogmat. Zamiast tego „ukrywanie” czegoś jest dobrą praktyką, aby ułatwić zapoznanie się z pewnym interfejsem API. Ukryłbyś na przykład bardzo podstawowe obliczenia nowego bloku konstrukcyjnego termometru cyfrowego - nie po to, aby ukryć matematykę za rzeczywistą zmierzoną krzywą dla ciekawskich czytników kodów, ale aby zapobiec uzależnieniu kodu od niektórych, być może nagle ważni użytkownicy, którzy nie mogliby się oprzeć użyciu twojego wcześniej prywatnego, wewnętrznego, chronionego kodu do realizacji własnych pomysłów.
O czym mówię
Łatwo jest ogłosić Wiek Wodnika lub to, co nazywa się obecnie, ale jeśli mój kawałek czujnika zmieni się z 1.0 na 2.0, implementacja Tłumacz ... może zmienić się z prostego równania liniowego, które jest łatwo zrozumiałe i „ponownie” użyteczny dla wszystkich, do dość wyrafinowanych obliczeń, które wykorzystują analizę lub cokolwiek innego, więc złamałbym kod innej osoby. Dlaczego? Ponieważ nie rozumieli samych zasad kodowania oprogramowania, nawet KIS.
Krótko mówiąc: potrzebujemy prostego sposobu na przetestowanie prywatnych metod - bez zbędnych ceregieli.
Po pierwsze: Szczęśliwego nowego roku wszystkim!
Po drugie: przećwicz lekcje architekta.
Po trzecie: „publicznym” modyfikatorem jest religia, a nie rozwiązanie.
źródło
Inną opcją, o której nie wspomniano, jest po prostu utworzenie klasy testu jednostkowego jako elementu potomnego testowanego obiektu. Przykład NUnit:
Umożliwiłoby to łatwe testowanie prywatnych i chronionych (ale nie odziedziczonych prywatnych) metod, a także pozwoliłoby oddzielić wszystkie testy od rzeczywistego kodu, aby nie wdrażać zestawów testowych w środowisku produkcyjnym. Przełączenie metod prywatnych na chronione byłoby dopuszczalne w wielu odziedziczonych obiektach i jest to dość prosta zmiana.
JEDNAK...
Chociaż jest to interesujące podejście do rozwiązania problemu testowania ukrytych metod, nie jestem pewien, czy zaleciłbym, aby we wszystkich przypadkach było to właściwe rozwiązanie problemu. Wydaje się trochę dziwne wewnętrzne testowanie obiektu i podejrzewam, że mogą istnieć pewne scenariusze, że takie podejście cię wysadzi. (Na przykład niezmienne obiekty mogą utrudnić niektóre testy).
Wspominając o tym podejściu, sugeruję, że jest to raczej sugestia burzy mózgów niż uzasadnione rozwiązanie. Dodaj szczyptę soli.
EDYCJA: Uważam, że to naprawdę zabawne, że ludzie głosują na tę odpowiedź, ponieważ wyraźnie opisuję to jako zły pomysł. Czy to oznacza, że ludzie się ze mną zgadzają? Jestem taki skołowany.....
źródło
Z książki Skuteczna praca ze starszym kodem :
Według autora sposobem na jego naprawienie jest utworzenie nowej klasy i dodanie metody as
public
.Autor wyjaśnia dalej:
Tak więc, w tych granicach, jedyną prawdziwą opcją jest stworzenie metody
public
w bieżącej lub nowej klasie.źródło
TL; DR: Wyodrębnij metodę prywatną do innej klasy, przetestuj na tej klasie; czytaj więcej o zasadzie SRP (zasada pojedynczej odpowiedzialności)
Wydaje się, że potrzebujesz wyciągu z
private
metody do innej klasy; w tym powinno byćpublic
. Zamiast próbować testowaćprivate
metodę, powinieneś przetestowaćpublic
metodę tej innej klasy.Mamy następujący scenariusz:
Musimy przetestować logikę
_someLogic
; ale wydaje się, żeClass A
odgrywają większą rolę niż to konieczne (narusza zasadę SRP); po prostu podziel na dwie klasyW ten sposób
someLogic
można przetestować na A2; w A1 po prostu stwórz fałszywy A2, a następnie wstrzyknij do konstruktora, aby sprawdzić, czy A2 jest wywoływany do funkcji o nazwiesomeLogic
.źródło
W VS 2005/2008 możesz użyć prywatnego akcesora do przetestowania prywatnego członka, ale ten sposób zniknął w późniejszej wersji VS
źródło