2011-08-16 17 views
7

Istnieją różne opinie na temat znaczenia testowania prywatnych metod, np. here i here. Osobiście uważam, że ma to sens, pytanie brzmi: jak to zrobić właściwie. W języku C++ można użyć klasy #define hack lub utworzyć klasę testową friend, w języku C# jest InternalsVisibleToAttribute, ale w języku Java musimy albo użyć reflection lub uczynić je "widocznymi do testowania" i annotate them as such w celu wyjaśnienia zamiaru. Wady obu powinny być całkiem jasne.Narzędzie Java do testowania prywatnych metod?

Myślę, że powinno być coś lepszego. Począwszy od

public class Something { 
    private int internalSecret() { 
     return 43; 
    } 
} 

byłoby miło, aby móc wywoływać metod prywatnych w kodzie testowym jak

@MakeVisibleForTesting Something something = new Something(); 
Assert.assertEquals(43, something.internalSecret()); 

tu adnotacja będzie cicho przekształcić wszystkie połączenia do prywatnych metod something użyciu odbicia. Zastanawiam się, czy może to zrobić Lombok (i zapytam autorów).

Jest całkiem możliwe, że wykonanie tej magii okaże się zbyt skomplikowane, a w każdym razie zajmie to trochę czasu, więc szukam innej alternatywy. Może adnotacji klasę badanego z czymś @Decapsulate i stosując procesor adnotacji do generowania klasy Decapsulated_Something patrząc jak

public class Decapsulated_Something { 
    public Decapsulated_Something(Something delegate) { 
     this.delegate = delegate 
    } 
    public boolean internalSecret() { 
     // call "delegate.internalSecret()" using reflection 
    } 
    ... 
} 

co pozwoliłoby korzystać

Decapsulated_Something something = new Decapsulated_Something(new Something()); 
Assert.assertEquals(43, something.internalSecret()); 

Nie mam dużego doświadczenia z adnotacją przetwarzanie, więc pytam najpierw tutaj:

  • Jak skomplikowane jest to wdrożenie?
  • O czym zapomniałem?
  • Co sądzisz o tym w ogóle?
+0

Czy pytasz fir narzędzie, lub jak napisać samemu? – Raedwald

+0

@Raedwald Pytam, jak go rozwiązać. Zużywanie się jest jedną z opcji, ale wymyślanie koła na nowo nie jest jednoznacznie pożądane. – maaartinus

Odpowiedz

1

byłoby miło, aby móc wywoływać metod prywatnych w kodzie testowym jak

@MakeVisibleForTesting Something something = new Something(); 
Assert.assertEquals(43, something.internalSecret()); 

Nie ma czegoś takiego jak metoda z adnotacją, sprawdź dp4j „s @TestPrivates:

@Test 
@TestPrivates 
//since the method is annotated with JUnit's @Test this annotation is redundant. 
// You just need to have dp4j on the classpath. 
    public void somethingTest(){ 
     Something something = new Something(); 
     int sthSecret = something.internalSecret(); 
     Assert.assertEquals(43, sthSecret); //cannot use something.internalSecret() directly because of bug [dp4j-13][2] 
    } 
7

Wygląda na to, że wykonanie tej implementacji jest trudne. Może nie być tego warte. Zamiast tego ustaw domyślnie pakiet metod.

Jeśli jednak jesteś zdecydowany na wywołanie metody prywatnej, możesz użyć klasy setAccessible w klasie Decapsulated_something, aby umożliwić rozmowę przez odbicie. Jest to dość proste.

+0

+1 dla pakietu prywatnego. – Thilo

1

Odpowiem na pytanie "W ogóle" :-) Wystarczy kilka linii kodu, aby metoda była dostępna za pomocą refleksji, a istnieje wiele bibliotek, narzędzi, interfejsów API itp., Które zapewniają metody wykonywania więc. Istnieje również wiele różnych technik, których możesz użyć we własnym kodzie. Na przykład manipulowanie kodami bajtowymi, odbicia, rozszerzenia klas itp. Byłbym jednak skłonny do prostoty. Choć może być użyteczne testowanie prywatnych metod, prawdopodobnie będziesz chciał przetestować tylko kilka. Więc inżynieria czegoś złożonego jest prawdopodobnie przesadą. Po prostu używałbym ustalonego API lub napisałem szybką metodę dostępu do prywatnych metod, które mnie interesowały, i niech to się stanie.

1

Istnieje wiele podejść do podjęcia

  • Nie testowania metod prywatnych, ponieważ są one ukryte szczegóły implementacji, które nigdy nie powinny mieć znaczenie dla rozmówcy.
  • Utwórz pakiet metod, aby dzwoniący nie mógł uzyskać do nich dostępu, ale możesz uzyskać do nich dostęp w tym samym pakiecie, np. Test jednostkowy.
  • Spraw, aby jednostka testowała wewnętrzną klasę lub zapewniła lokalną wewnętrzną klasę pakietu. Nie jestem pewien, czy to jest poprawa!
  • Użyj refleksji, aby uzyskać dostęp do metod klasy. To jest jak oznaczanie metody rpivate, gdy jej IMHO jest nieporozumieniem. Powinieneś tylko oznaczać metodę jako prywatną, gdy jest naprawdę prywatna.
1

Pracowałem nad projektem kilka lat temu, który generował klasy, aby ułatwić testowanie prywatnych metod jednostkowych. http://java.net/projects/privateer/

Generuje dodatkowe klasy, które ułatwiają odczytywanie odwołań, np. gdybyś miał MyClass.myPrivateMethod(), generowałby klasę _MyClass, która pozwalałaby na bezpośrednie wywoływanie myPrivateMethod.

To nigdy nie było naprawdę zakończone i było przydatne w kilku przypadkach, ale ogólnie nie polecałbym testowania prywatnych metod, chyba że jest to absolutnie konieczne. Zwykle lepszym rozwiązaniem jest przebudowanie ich na klasy użytkowe (z dostępem do pakietu, jeśli obawiasz się, że użytkownicy ich używają).

Powiązane problemy