Jak przetestować prywatną funkcję lub klasę, która ma prywatne metody, pola lub klasy wewnętrzne?

Jak przetestować (używając xUnit) klasę, która ma wewnętrzne prywatne metody, pola lub zagnieżdżone klasy? Lub funkcja, która jest prywatna przez wewnętrzne powiązanie (static W C / C++) czy jest w prywatnej ( anonymous ) przestrzeni nazw?

Źle wydaje się zmieniać modyfikator dostępu dla metody lub funkcji tylko po to, aby móc uruchomić test.

Author: Raedwald, 2008-08-29

30 answers

Jeśli posiadasz jakąś spuściznę Java i nie możesz zmieniać widoczności swoich metod, najlepszym sposobem testowania prywatnych metod jest użycie reflection.

Wewnętrznie używamy helperów, aby uzyskać / ustawić zmienne private i private static, a także wywołać metody private i private static. Poniższe wzorce pozwolą Ci zrobić prawie wszystko związane z prywatnymi metodami i polami. Oczywiście nie można zmienić private static final zmiennych poprzez odbicie.

Method method = targetClass.getDeclaredMethod(methodName, argClasses);
method.setAccessible(true);
return method.invoke(targetObject, argObjects);

I dla pól:

Field field = targetClass.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);

Uwagi:
1. targetClass.getDeclaredMethod(methodName, argClasses) pozwala przyjrzeć się metodom private. To samo dotyczy getDeclaredField.
2. {[10] } jest wymagane do zabawy z szeregowcami.

 1443
Author: Cem Catikkas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-14 17:14:57

Najlepszym sposobem na przetestowanie metody prywatnej jest inna metoda publiczna. Jeśli nie można tego zrobić, to spełniony jest jeden z następujących warunków:

  1. metoda prywatna to martwy kod
  2. w pobliżu klasy jest zapach projektu, który Testujesz
  3. metoda, którą próbujesz przetestować nie powinna być prywatna
 519
Author: Trumpi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-29 16:14:19

Kiedy mam prywatne metody w klasie, które są na tyle skomplikowane, że czuję potrzebę przetestowania prywatnych metod bezpośrednio, to jest zapach kodu: moja klasa jest zbyt skomplikowana.

Moim zwyczajowym podejściem do rozwiązywania takich problemów jest dokuczanie nowej klasie, która zawiera interesujące bity. Często ta metoda i pola, z którymi współdziała, i być może inna metoda lub dwie mogą zostać wyodrębnione do nowej klasy.

Nowa klasa ujawnia te metody jako 'publiczne', więc są dostępne do testów jednostkowych. Nowe i stare klasy są teraz zarówno prostsze niż oryginalna Klasa, co jest dla mnie świetne (muszę zachować rzeczy proste, albo się zgubić!).

Zauważ, że nie sugeruję, że ludzie tworzą klasy bez użycia mózgu! Chodzi o to, aby wykorzystać siły testów jednostkowych, aby pomóc Ci znaleźć dobre nowe klasy.

 275
Author: Jay Bazuzi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-19 09:38:59

W przeszłości używałem reflection, aby zrobić to dla Javy i moim zdaniem był to duży błąd.

Ściśle mówiąc, powinieneś a nie pisać testy jednostkowe, które bezpośrednio testują prywatne metody. To, co powinieneś testować, to zamówienie publiczne, które klasa ma z innymi obiektami; nigdy nie powinieneś bezpośrednio testować wewnętrznych obiektów. Jeśli inny programista chce wprowadzić małą wewnętrzną zmianę do klasy, która nie wpływa na publiczne klasy kontrakt, on / ona następnie musi zmodyfikować swój test oparty na refleksji, aby upewnić się, że działa. Jeśli zrobisz to wielokrotnie w trakcie całego projektu, testy jednostkowe przestaną być użytecznym pomiarem stanu kodu i zaczną stać się przeszkodą w rozwoju i irytacją dla zespołu programistów.

Zamiast tego zalecam użycie narzędzia do pokrycia kodu, takiego jak Cobertura, aby upewnić się, że testy jednostkowe, które piszesz, zapewniają przyzwoite pokrycie kodu w metodach prywatnych. W ten sposób, ty pośrednio sprawdzić, co robią prywatne metody i utrzymać wyższy poziom zwinności.

 236
Author: Jon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-14 12:19:35

Z tego artykułu: testowanie prywatnych metod za pomocą JUnit i SuiteRunner (Bill Venners), masz w zasadzie 4 opcje:

    Nie testuj prywatnych metod.
  • dać dostęp do pakietu metod.
  • Użyj zagnieżdżonej klasy testowej.
  • Użyj refleksji.
 187
Author: Iker Jimenez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-21 20:45:56

Ogólnie test jednostkowy jest przeznaczony do korzystania z publicznego interfejsu klasy lub jednostki. Dlatego metody prywatne są szczegółami implementacji, których nie można oczekiwać, aby testować jawnie.

 99
Author: John Channing,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-29 09:52:20

Tylko dwa przykłady gdzie chciałbym przetestować prywatną metodę:

  1. procedury deszyfrowania - nie chciałbym chcesz, aby były widoczne dla każdego, aby zobaczyć tylko dla ze względu na testowanie, inaczej każdy może użyj ich do odszyfrowania. Ale są nieodłączny do kodu, skomplikowany, i muszą zawsze działać (oczywistym wyjątkiem jest reflection, które może być używane do przeglądania nawet prywatnych metod w większości przypadków, gdy SecurityManager nie jest skonfigurowane, aby temu zapobiec).
  2. Tworzenie SDK dla społeczności konsumpcja. Tutaj publicznie bierze na zupełnie inne znaczenie, ponieważ to to kod, który może zobaczyć cały świat (nie tylko wewnętrzne do mojej aplikacji). I put kod do metod prywatnych, jeśli nie chcesz, aby użytkownicy SDK to zobaczyli-I nie postrzegaj tego jako zapachu kodu, tylko jak działa programowanie SDK. Ale z oczywiście muszę jeszcze przetestować mój prywatne metody, i są tam, gdzie funkcjonalność mojego SDK życia.

Rozumiem ideę testowania tylko "kontrakt". Ale nie widzę, żeby można było opowiadać się za nie testowaniem kodu - przebieg może się różnić.

Więc mój kompromis polega na komplikowaniu Junitów z refleksją, zamiast narażać moje Bezpieczeństwo i SDK.

 56
Author: Richard Le Mesurier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-13 19:24:04

Metody prywatne są wywoływane przez metodę publiczną, więc dane wejściowe do Twoich metod publicznych powinny również testować metody prywatne, które są wywoływane przez te metody publiczne. Jeśli metoda publiczna zawiedzie, to może to być awaria w metodzie prywatnej.

 53
Author: Thomas Owens,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-29 16:15:30

Innym podejściem, które zastosowałem, jest zmiana metody prywatnej na pakiet prywatny lub chroniony, a następnie uzupełnienie jej adnotacją @VisibleForTesting biblioteki Google Guava.

To powie każdemu używającemu tej metody, aby zachowywał ostrożność i nie uzyskiwał do niej bezpośredniego dostępu, nawet w pakiecie. Również Klasa testowa nie musi znajdować się w tym samym pakiecie fizycznie, ale w tym samym pakiecie w folderze test.

Na przykład, jeśli badana metoda jest w src/main/java/mypackage/MyClass.java następnie Twoje wywołanie testowe powinno być umieszczone w src/test/java/mypackage/MyClassTest.java. W ten sposób uzyskasz dostęp do metody testowej w klasie testowej.

 30
Author: Peter Mortensen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-13 19:58:57

Aby przetestować legacy code z dużymi i dziwacznymi klasami, często bardzo pomocne jest przetestowanie jednej prywatnej (lub publicznej) metody, którą teraz piszę .

Używam junitx.util.PrivateAccessor - pakiet dla Javy . Wiele przydatnych jednolinijek do uzyskiwania dostępu do prywatnych metod i prywatnych pól.

import junitx.util.PrivateAccessor;

PrivateAccessor.setField(myObjectReference, "myCrucialButHardToReachPrivateField", myNewValue);
PrivateAccessor.invoke(myObjectReference, "privateMethodName", java.lang.Class[] parameterTypes, java.lang.Object[] args);
 28
Author: phareim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-14 12:20:38

Po wypróbowaniu rozwiązania Cem Catikkas za pomocą reflection dla Javy, muszę powiedzieć, że jego rozwiązanie było bardziej eleganckie niż opisałem tutaj. Jeśli jednak szukasz alternatywy dla używania reflection i masz dostęp do testowanego źródła, nadal będzie to opcja.

Jest możliwa zasługa w testowaniu prywatnych metod klasy, szczególnie z test-driven development , gdzie chciałbyś zaprojektować małe testy przed napisaniem jakichkolwiek kod.

Tworzenie testu z dostępem do prywatnych członków i metod może testować obszary kodu, które są trudne do ukierunkowania specjalnie z dostępem tylko do publicznych metod. Jeśli metoda publiczna składa się z kilku kroków, może składać się z kilku metod prywatnych, które można następnie przetestować indywidualnie.

Zalety:

    Może testować do drobniejszej ziarnistości [16]}

Wady:

  • kod testowy musi znajdować się w tym samym plik jako kod źródłowy, który może be trudniejsze w utrzymaniu
  • podobnie z .pliki wyjściowe klasy, muszą pozostać w tym samym pakiecie, co zadeklarowane w kodzie źródłowym

Jednakże, jeśli ciągłe testowanie wymaga tej metody, może to być sygnał, że prywatne metody powinny zostać wyodrębnione, które mogą być testowane w tradycyjny, publiczny sposób.

Oto zawiły przykład tego, jak to będzie działać:

// Import statements and package declarations

public class ClassToTest
{
    private int decrement(int toDecrement) {
        toDecrement--;
        return toDecrement;
    }

    // Constructor and the rest of the class

    public static class StaticInnerTest extends TestCase
    {
        public StaticInnerTest(){
            super();
        }

        public void testDecrement(){
            int number = 10;
            ClassToTest toTest= new ClassToTest();
            int decremented = toTest.decrement(number);
            assertEquals(9, decremented);
        }

        public static void main(String[] args) {
            junit.textui.TestRunner.run(StaticInnerTest.class);
        }
    }
}

Klasa wewnętrzna zostanie skompilowana do ClassToTest$StaticInnerTest.

Zobacz: Java Tip 106: statyczne klasy wewnętrzne dla zabawy i zysku

 24
Author: Grundlefleck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-14 12:22:32

Jak mówili inni... nie testuj prywatnych metod bezpośrednio. Oto kilka myśli:

  1. Zachowaj wszystkie metody małe i skupione (łatwe do przetestowania, łatwe do znalezienia, co jest nie tak)
  2. Użyj narzędzi do pokrycia kodu. I likeCobertura (Oh happy day, looks like a new version is out!)

Uruchom pokrycie kodu w testach jednostkowych. Jeśli zobaczysz, że metody nie są w pełni przetestowane, Dodaj do testów, aby zwiększyć zasięg. Dążyć do 100% pokrycia kodu, ale zdaj sobie sprawę, że prawdopodobnie nie dostanie.

 21
Author: TofuBeer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-13 19:13:20

Metody prywatne są wykorzystywane przez metody publiczne. W przeciwnym razie to martwy kod. Dlatego testujesz metodę publiczną, potwierdzając oczekiwane wyniki metody publicznej, a tym samym metody prywatne, które ona wykorzystuje.

Testowanie prywatnych metod powinno być testowane przez debugowanie przed uruchomieniem testów jednostkowych na metodach publicznych.

Mogą być również debugowane za pomocą Test-driven development, debugowanie testów jednostkowych, dopóki wszystkie Twoje twierdzenia nie zostaną spełnione.

Ja osobiście w to wierzę lepiej jest tworzyć klasy przy użyciu TDD; tworzenie publicznych stubów metody, następnie generowanie testów jednostkowych z wszystkimi twierdzeniami zdefiniowanymi z góry, więc oczekiwany wynik metody jest ustalany przed jej zakodowaniem. W ten sposób nie idziesz złą ścieżką, aby twierdzenia testu jednostkowego pasowały do wyników. Twoja klasa jest wtedy solidna i spełnia wymagania, gdy wszystkie testy jednostkowe przechodzą.

 20
Author: Antony Booth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-13 19:33:13

Jeśli używasz sprężyny, Reflectestutils zapewnia kilka przydatnych narzędzi, które pomagają tutaj przy minimalnym wysiłku. Na przykład, aby skonfigurować makietę na prywatnym członie bez konieczności dodawania niepożądanego publicznego settera:

ReflectionTestUtils.setField(theClass, "theUnsettableField", theMockObject);
 19
Author: Steve Chambers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-10 23:36:00

Jeśli próbujesz przetestować istniejący kod, którego nie jesteś w stanie zmienić lub nie jesteś w stanie go zmienić, dobrym wyborem będzie reflection.

Jeśli konstrukcja klasy jest nadal elastyczna, a masz skomplikowaną metodę prywatną, którą chciałbyś przetestować osobno, sugeruję, abyś wyciągnął ją do osobnej klasy i przetestował ją osobno. To nie musi zmieniać publicznego interfejsu oryginalnej klasy; może wewnętrznie utworzyć instancję klasy pomocniczej i wywołać helper metoda.

Jeśli chcesz przetestować trudne warunki błędów pochodzące z metody pomocniczej, możesz pójść o krok dalej. Wyodrębnij interfejs z klasy pomocniczej, dodaj publiczny getter i setter do oryginalnej klasy, aby wstrzyknąć klasę pomocniczą (używaną przez jej interfejs), a następnie wstrzyknij wzorcową wersję klasy pomocniczej do oryginalnej klasy, aby sprawdzić, jak oryginalna Klasa reaguje na wyjątki z helpera. Takie podejście jest również pomocne, jeśli chcesz przetestować oryginalną klasę bez testowania klasy pomocniczej.

 19
Author: Don Kirkby,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-13 19:08:28

W Spring Framework możesz przetestować prywatne metody używając tej metody:

ReflectionTestUtils.invokeMethod()

Na przykład:

ReflectionTestUtils.invokeMethod(TestClazz, "createTest", "input data");
 17
Author: Mikhail,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-13 19:57:12

Testowanie prywatnych metod łamie enkapsulację twojej klasy, ponieważ za każdym razem, gdy zmieniasz wewnętrzną implementację, łamiesz kod klienta (w tym przypadku testy).

Więc nie testuj prywatnych metod.

 15
Author: Peter Mortensen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-29 10:02:43

Jeśli chcesz przetestować prywatne metody starszej aplikacji, w której nie możesz zmienić kodu, jedną z opcji dla Javy jest jMockit , która pozwoli Ci tworzyć mocki do obiektu nawet wtedy, gdy są prywatne do klasy.

 14
Author: Will Sargent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-14 12:23:33

Jeśli używasz JUnit, spójrz na junit-addons . Ma możliwość ignorowania modelu bezpieczeństwa Java i dostępu do prywatnych metod i atrybutów.

 13
Author: Joe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-14 12:24:27

Nie testuję prywatnych metod. Tam leży szaleństwo. Osobiście uważam, że powinieneś testować tylko publicznie ujawnione interfejsy (a to obejmuje metody chronione i wewnętrzne).

 12
Author: bmurphy1976,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-29 16:23:45

Odpowiedź z JUnit.org strona FAQ :

Ale jeśli musisz...

Jeśli używasz JDK 1.3 lub wyższej, możesz użyć reflection, aby obalić mechanizm kontroli dostępu przy pomocy PrivilegedAccessor . Aby dowiedzieć się, jak z niego korzystać, przeczytaj Ten artykuł .

Jeśli używasz JDK 1.6 lub nowszego i opisujesz swoje testy za pomocą @Test, możesz użyć Dp4j aby wprowadzić odbicie w swoich metodach testowych. Na szczegóły na jak go używać, zobacz ten skrypt testowy .

P. S. jestem głównym współpracownikiem Dp4j , zapytaj mnie jeśli potrzebujesz pomocy. :)

 12
Author: simpatico,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:55:10

Metoda prywatna jest dostępna tylko w ramach tej samej klasy. Nie ma więc możliwości przetestowania "prywatnej" metody klasy docelowej z żadnej klasy testowej. Wyjściem jest to, że możesz wykonać testy jednostkowe ręcznie lub zmienić metodę z "prywatnej"na " chronioną".

I wtedy metoda chroniona może być dostępna tylko w tym samym pakiecie, w którym zdefiniowana jest klasa. Testowanie chronionej metody klasy docelowej oznacza, że musimy zdefiniować klasę testową w tym samym pakiecie co Klasa docelowa.

Jeśli wszystko powyższe nie odpowiada Twoim wymaganiom, użyj droga refleksji aby uzyskać dostęp do metody prywatnej.

 11
Author: loknath,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:29

Sugerowałbym, żebyś trochę refaktoryzował swój kod. Kiedy musisz zacząć myśleć o używaniu reflection lub innych rzeczy, do testowania kodu, coś jest nie tak z Twoim kodem.

Wspomniałeś o różnych rodzajach problemów. Zacznijmy od prywatnych pól. W przypadku prywatnych pól dodałbym nowy konstruktor i wstawiłbym do niego pola. Zamiast tego:
public class ClassToTest {

    private final String first = "first";
    private final List<String> second = new ArrayList<>();
    ...
}

Użyłbym tego:

public class ClassToTest {

    private final String first;
    private final List<String> second;

    public ClassToTest() {
        this("first", new ArrayList<>());
    }

    public ClassToTest(final String first, final List<String> second) {
        this.first = first;
        this.second = second;
    }
    ...
}

To nie będzie problem nawet z jakiś kod. Stary kod będzie używał pustego konstruktora, a jeśli mnie zapytasz, refactored code będzie wyglądał czystiej i będziesz mógł wprowadzić niezbędne wartości w teście bez refleksji.

Teraz o metodach prywatnych. Z mojego osobistego doświadczenia wynika, że kiedy musisz przejść prywatną metodę testowania, to ta metoda nie ma nic wspólnego z tą klasą. Często spotykanym wzorcem, w takim przypadku, byłoby zawinięcie wewnątrz interfejsu, jak Callable, a następnie Przejście W tym interfejsie również w konstruktor (z tym trikiem konstruktora wielokrotnego):

public ClassToTest() {
    this(...);
}

public ClassToTest(final Callable<T> privateMethodLogic) {
    this.privateMethodLogic = privateMethodLogic;
}

Głównie wszystko, co napisałem, wygląda na wzór wtrysku zależności. Z mojego osobistego doświadczenia wynika, że jest to bardzo przydatne podczas testowania i myślę, że ten rodzaj kodu jest czystszy i będzie łatwiejszy w utrzymaniu. Powiedziałbym to samo o klasach zagnieżdżonych. Jeśli zagnieżdżona klasa zawiera ciężką logikę, byłoby lepiej, gdybyś przeniósł ją jako prywatną klasę pakietu i wstrzyknął do potrzebującej jej klasy.

Istnieją również kilka innych wzorców projektowych, które wykorzystałem podczas refaktoryzacji i utrzymywania kodu starszego, ale wszystko zależy od przypadków kodu do przetestowania. Korzystanie z reflection w większości nie jest problemem, ale gdy masz aplikację korporacyjną, która jest mocno testowana i testy są uruchamiane przed każdym wdrożeniem, wszystko robi się naprawdę powolne (to jest po prostu denerwujące i nie lubię tego typu rzeczy).

Jest też zastrzyk settera, ale nie zalecałbym go używać. Lepiej zostanę przy konstruktorze i inicjalizować wszystko, gdy jest to naprawdę konieczne, pozostawiając możliwość wstrzykiwania niezbędnych zależności.

 11
Author: GROX13,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-13 20:05:12

Jak wielu powyżej zasugerowało, dobrym sposobem jest przetestowanie ich za pośrednictwem publicznych interfejsów.

Jeśli to zrobisz, dobrym pomysłem jest użycie narzędzia do pokrycia kodu (takiego jak Emma), aby sprawdzić, czy twoje prywatne metody są faktycznie wykonywane z Twoich testów.

 10
Author: Darren Greaves,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-10 07:48:42

Oto moja ogólna funkcja do testowania prywatnych pól:

protected <F> F getPrivateField(String fieldName, Object obj)
    throws NoSuchFieldException, IllegalAccessException {
    Field field =
        obj.getClass().getDeclaredField(fieldName);

    field.setAccessible(true);
    return (F)field.get(obj);
}
 9
Author: Yuli Reiri,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-13 19:33:48

Proszę zobaczyć poniżej przykład;

Należy dodać Oświadczenie o przywozie w brzmieniu:

import org.powermock.reflect.Whitebox;

Teraz możesz bezpośrednio przekazać obiekt, który ma metodę prywatną, nazwę metody do wywołania oraz dodatkowe parametry jak poniżej.

Whitebox.invokeMethod(obj, "privateMethod", "param1");
 9
Author: Olcay Tarazan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-13 19:59:42

Dzisiaj wypchnąłem bibliotekę Javy, aby pomóc w testowaniu prywatnych metod i pól. Został zaprojektowany z myślą o Androidzie, ale naprawdę może być używany w każdym projekcie Java.

Jeśli masz jakiś kod z prywatnymi metodami, polami lub konstruktorami, możesz użyć BoundBox. Robi dokładnie to, czego szukasz. Poniżej znajduje się przykład testu, który uzyskuje dostęp do dwóch prywatnych pól aktywności na Androidzie, aby ją przetestować:

@UiThreadTest
public void testCompute() {

    // Given
    boundBoxOfMainActivity = new BoundBoxOfMainActivity(getActivity());

    // When
    boundBoxOfMainActivity.boundBox_getButtonMain().performClick();

    // Then
    assertEquals("42", boundBoxOfMainActivity.boundBox_getTextViewMain().getText());
}

BoundBox ułatwia testowanie prywatne / chronione pola, metody i konstruktory. Możesz nawet uzyskać dostęp do rzeczy, które są ukryte przez dziedziczenie. Rzeczywiście, BoundBox łamie enkapsulację. To da ci dostęp do tego wszystkiego poprzez refleksję, ale wszystko jest sprawdzane podczas kompilacji.

Jest idealny do testowania kodu starszego typu. Używaj go ostrożnie. ;)

Https://github.com/stephanenicolas/boundbox

 9
Author: Snicolas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-14 12:25:37

Po pierwsze, wyrzucę to pytanie: dlaczego twoi prywatni członkowie potrzebują izolowanych testów? Czy są one tak złożone, zapewniając tak skomplikowane zachowania, że wymagają testowania poza powierzchnią publiczną? To testy jednostkowe, a nie "linia kodu". Nie przejmuj się drobiazgami.

Jeśli są na tyle duże, że każdy z nich jest 'jednostką' o dużej złożoności-rozważ refaktoryzację takich prywatnych członków z tej klasy.

Jeśli refaktoryzacja jest nieodpowiednie lub niewykonalne, czy możesz użyć wzorca strategii, aby zastąpić dostęp do tych prywatnych funkcji / klas członków w teście jednostkowym? W teście jednostkowym strategia zapewniłaby dodatkową walidację, ale w release builds byłaby prostym przejściem.

 7
Author: Aaron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-13 19:12:04

Ostatnio miałem ten problem i napisałem małe narzędzie o nazwie Picklock , które pozwala uniknąć problemów z jawnym użyciem Java reflection API, dwa przykłady:

Wywołanie metod, np. private void method(String s) - Przez Java reflection

Method method = targetClass.getDeclaredMethod("method", String.class);
method.setAccessible(true);
return method.invoke(targetObject, "mystring");

Wywołanie metod, np. private void method(String s) - Przez Picklock

interface Accessible {
  void method(String s);
}

...
Accessible a = ObjectAccess.unlock(targetObject).features(Accessible.class);
a.method("mystring");

Ustawianie pól, np. private BigInteger amount; - przez Java reflection

Field field = targetClass.getDeclaredField("amount");
field.setAccessible(true);
field.set(object, BigInteger.valueOf(42));

Ustawianie pól, np. private BigInteger amount; - przez Picklock

interface Accessible {
  void setAmount(BigInteger amount);
}

...
Accessible a = ObjectAccess.unlock(targetObject).features(Accessible.class);
a.setAmount(BigInteger.valueOf(42));
 7
Author: CoronA,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-13 19:56:35

Dla Javy użyłbym reflection , ponieważ nie podoba mi się pomysł zmiany dostępu do pakietu na zadeklarowanej metodzie tylko dla celów testowania. Zwykle jednak testuję tylko publiczne metody, które powinny również upewnić się, że metody prywatne działają poprawnie.

Nie możesz użyć reflection, aby uzyskać prywatne metody spoza klasy właściciela, modyfikator prywatny wpływa również na reflection

To nieprawda. Na pewno można, jak wspomniano w odpowiedź Cem Catikkasa .

 6
Author: Josh Brown,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-14 12:26:40