Używanie PowerMockito.whenNew () nie jest mockowane i wywoływana jest oryginalna metoda


104

Mam kod podobny do tego poniżej:

Class A {
  public boolean myMethod(someargs) {
    MyQueryClass query = new MyQueryClass();
    Long id = query.getNextId();
    // some more code
  }
}
Class MyQueryClass     {
  ....
  public Long getNextId() {
    //lot of DB code, execute some DB query
    return id;
  }
}

Teraz piszę test dla A.myMethod(someargs). Chcę pominąć prawdziwą metodę query.getNextId()i zamiast tego zwrócić wartość zastępczą. Zasadniczo chcę kpić MyQueryClass.

Więc w moim przypadku testowym użyłem:

MyQueryClass query = PowerMockito.mock(MyQueryClass.class);
PowerMockito.whenNew(MyQueryClass.class).withNoArguments().thenReturn(query);
when(query.getNextId()).thenReturn(1000000L);

boolean b = A.getInstance().myMethod(args);

//asserts

Użyłem @RunWith(PowerMockRunner.class)i @PrepareForTest({MyQueryClass.class})na początku mojej klasy testowej.

Ale kiedy debugowania test, to wciąż wywołując prawdziwą metodę getNextId()z MyQueryClassklasy.

Czego tu brakuje? Czy ktoś może pomóc, ponieważ jestem nowy w Mockito i PowerMockito.

Odpowiedzi:


230

Musisz umieścić w adnotacji klasę, w której konstruktor jest wywoływany,@PrepareForTest zamiast klasy, która jest konstruowana - zobacz Mock konstruowanie nowych obiektów .

W Twoim przypadku:

@PrepareForTest(MyQueryClass.class)

@PrepareForTest(A.class)

Bardziej ogólne:

@PrepareForTest(NewInstanceClass.class)

@PrepareForTest(ClassThatCreatesTheNewInstance.class)


1
Wielkie dzięki. Teraz zadziałało po uwzględnieniu aktualnej klasy Eg A w @PrepareForTest.
user3942446

2
Ja też poświęcam na to trochę czasu. Dzięki @TrueDub. Ponieważ odniesienie jest nieaktualne. Po prostu to aktualizuję. github.com/jayway/powermock/wiki/MockConstructor Mówi się: Użyj adnotacji @PrepareForTest (ClassThatCreatesTheNewInstance.class) na poziomie klasy przypadku testowego.
Victor Choy,

4
Mam ten sam problem, ale to rozwiązanie u mnie nie działa
dexter

3
To rozwiązanie po prostu nie zadziała, jeśli używasz eclemmy do pokrycia kodu. Dodanie testowanej klasy do @PrepareForTest spowoduje 0% pokrycia dla tej klasy
ACV

2
Rozwiązanie zadziała - test zostanie wykonany poprawnie. Oczywiście eclemma nie jest przystosowana do radzenia sobie z PowerMockito. Pokrycie kodu nie jest częścią tego pytania.
TrueDub

5

Jak @TrueDub wspomniał w swojej zaakceptowanej odpowiedzi, musisz dodać klasę, w której konstruktor jest wywoływany, do pliku @PrepareForTest.

Jeśli jednak to zrobisz, pokrycie dla tej klasy zgłoszone przez eclemma i Sonar będzie wynosić zero dla tej klasy

Powermockito wiki

Zamierzamy zastąpić Javassist ByteBuddy (# 727) i powinno to pomóc rozwiązać ten stary problem. Ale teraz NIE MA MOŻLIWOŚCI UŻYCIA PowerMock z instrumentami JaCoCo On-the-fly. I nie ma obejścia, aby uzyskać pokrycie kodu w IDE.

Tak więc rozwiązaniem tutaj byłoby zrefaktoryzowanie rzeczywistego kodu, aby używał statycznej fabryki, która zwróciłaby instancję tej klasy, a następnie statycznie z niej mockowała.


Zgadzam się z twoim komentarzem.
Lathy,

To nie jest problem w Intellij.
ACV

Uważam, że ma to wpływ tylko na klasę testową, w której użyłeś tej adnotacji, więc możesz odizolować te testy, aby zminimalizować wpływ. Całkowicie się zgadzam, że problem naprawdę polega na tym, że zajęcia nie zostały odpowiednio przygotowane do testów
Calabacin

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.