2009-07-29 20 views
15

Jak łatwo wyśmiewać metodę statyczną w Javie?Jak w prosty sposób wyobrazić metodę statyczną w Javie (jUnit4)?

Używam Wiosna JUnit 2.5 i 4.4

@Service 
public class SomeServiceImpl implements SomeService { 

    public Object doSomething() { 
     Logger.getLogger(this.class); //a static method invoked. 
     // ... 
    } 
} 

nie kontrolować metody statycznej, że moja usługa musi powołać więc nie Refactor to być bardziej unit-sprawdzalne. Użyłem jako przykładu Log4J Logger, ale prawdziwa statyczna metoda jest podobna. Nie można zmienić metody statycznej.

Doing pracy Grails, jestem przyzwyczajony do korzystania coś takiego:

def mockedControl = mockFor(Logger) 
mockControl.demand.static.getLogger{Class clazz-> … } 
… 
mockControl.verify() 

Jak mogę zrobić coś podobnego w Java?

+0

Czy możesz zmienić implementację SomeServiceImpl? –

+0

Nieważne, Jon Skeet właśnie opublikował to, co myślałem. Czuję się dumny! (myśląc jak Jon Skeet hehe) –

+0

Tak, mogę zmienić SomeServiceImpl, ale dlaczego powinienem? Dlaczego dodatkowe pośrednictwo? –

Odpowiedz

0

Zasadniczo nie ma łatwego sposobu na zrobienie tego w Javie + Spring 2.5 & JUnit 4.4 w tej chwili.

Mimo że możliwe jest refaktoryzowanie i abstrakcyjne wywoływanie statyczne, Refaktoryzacja kodu nie jest rozwiązaniem, którego szukałem.

JMockit wyglądał, jakby działał, ale jest niekompatybilny ze Spring 2.5 i JUnit 4.4.

+2

PowerMock został zasugerowany i jest w stanie kpić z metod statycznych, więc jest łatwy sposób. – Richard

+0

PowerMock ma poważne wycieki pamięci, które odkryliśmy po obejrzeniu użycia pamięci i czasu trwania naszych kompilacji Jenkinsa, gdy użyliśmy pluginu maven, który automatycznie wykonałby testy jednostkowe, aby zapewnić jakość wykonania. Właśnie dlatego PowerMock jest złym rozwiązaniem. – Igor

+0

Sprawdź to, https://blog.jayway.com/2014/11/29/using-another-junit-runner-with-powermock/ Możesz @RunWith (PowerMockRunner.class), a następnie przekazać do @PowerMockRunnerDelegate (SpringJUnit4ClassRunner .klasa). Oczywiście będzie to wymagało pracy z kilkoma najnowszymi wersjami. – Yasin

14

Masz na myśli, że nie możesz kontrolować kodu wywołującego? Ponieważ jeśli kontrolujesz wywołania metodą statyczną, ale nie samą implementacją, możesz z łatwością wykonać to testowanie. Utwórz interfejs zależności za pomocą pojedynczej metody z tym samym podpisem, co metoda statyczna. Twoja implementacja produkcyjna po prostu zadzwoni do metody statycznej, ale wszystko, co aktualnie wywołuje metodę statyczną, będzie wywoływać za pośrednictwem interfejsu.

Możesz następnie wyśmiewać ten interfejs w normalny sposób.

1
public interface LoggerWrapper { 
    public Logger getLogger(Class<?> c); 
    } 
public class RealLoggerWrapper implements LoggerWrapper { 
    public Logger getLogger(Class<?> c) {return Logger.getLogger(c);} 
    } 
public class MockLoggerWrapper implements LoggerWrapper { 
    public Logger getLogger(Class<?> c) {return somethingElse;} 
    } 
0

To jeden z powodów, dla których statyczne metody są złe.

Przeprojektowaliśmy większość naszych fabryk tak, aby miały także seterów, abyśmy mogli w nich wprowadzić fałszywe obiekty. W rzeczywistości wymyśliliśmy coś w rodzaju zastrzyku zależności, w którym jedna metoda działała jak fabryka dla wszystkich naszych singletonów.

W twoim przypadku dodanie metody Logger.setLogger() (i zapisanie tej wartości) może działać. Jeśli musisz, możesz rozszerzyć klasę rejestratora i śledzić metodę getLogger także swoją własną.

4

Struktura JMockit obiecuje umożliwić kpiny ze statycznych metod.

https://jmockit.dev.java.net/

W rzeczywistości, to sprawia, że ​​pewne dość śmiałe roszczeń, w tym, że metody statyczne są całkowicie poprawny wybór projektu, a ich stosowanie nie powinno być ograniczone ze względu na nieadekwatność ram testowych.

Niezależnie od tego, czy takie twierdzenia są uzasadnione, sama struktura JMockit jest całkiem interesująca, chociaż nie wypróbowałem jeszcze tego.

+1

Stosowanie metod statycznych zawsze będzie kontrowersyjne. Ale czy ktoś może naprawdę argumentować przeciwko rozsądnemu użyciu słowa kluczowego final? Rozważmy na przykład, co ma do powiedzenia książka "Efektywna Java" (punkt 17). –

+1

Kiedy zajrzałem do korzystania z JMockit, stwierdziłem, że Spring 2.5.x jest niekompatybilny z JUnit 4.5+ i że JMockit jest kompatybilny z JUnit 4.4 (i poniżej) patrz http://jira.springframework.org/browse/SPR-5145 przez http://stackoverflow.com/questions/693115/junit4-spring-2-5-asserts-throw-noclassdeffounderror –

+0

Na razie JMockit nie wchodzi w grę. –

0

Możesz użyć AspectJ do przechwycenia statycznego wywołania metody i zrobić coś pożytecznego dla twojego testu.

+1

Jak to zrobić? Czy istnieje prosty przykład? –

1

Jako inną odpowiedź powyżej, JMockit może kpić z metod statycznych (i cokolwiek innego, jak również).

Ma nawet bezpośrednie wsparcie dla ram logowania. Na przykład można napisać:


@UsingMocksAndStubs(Log4jMocks.class) 
public class SomeServiceTest 
{ 
    // All test methods in this class will have any calls 
    // to the Log4J API automatically stubbed out. 
} 

Jednak obsługa JUnit 4.4 została przerwana. Obsługiwane są JUnit 3.8, JUnit 4.5+ i TestNG 5.8+.

4

PowerMock ma tę zdolność. Może także kpić z obiektów należących do klasy w trakcie testu. Jeśli twoja testowana metoda wywoła nową funkcję Foo(), możesz utworzyć próbny obiekt dla tego Foo i zastąpić go w testowanej metodzie.

Możliwe są również takie konstrukcje, jak tłumienie konstruktorów i inicjatory statyczne. Wszystkie te rzeczy są uważane za niezrównany kod i dlatego nie zaleca się tego robić, ale jeśli masz starszy kod, zmiana nie zawsze jest opcją. Jeśli jesteś na tym stanowisku, może ci pomóc PowerMock.

Powiązane problemy