Die Verwendung von PowerMockito.whenNew () wird nicht verspottet und die ursprüngliche Methode wird aufgerufen

99

Ich habe einen Code wie diesen unten:

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;
  }
}

Jetzt schreibe ich einen Test für A.myMethod(someargs). Ich möchte die reale Methode überspringen query.getNextId()und stattdessen einen Stub-Wert zurückgeben. Grundsätzlich möchte ich verspotten MyQueryClass.

In meinem Testfall habe ich also Folgendes verwendet:

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

Ich habe @RunWith(PowerMockRunner.class)und @PrepareForTest({MyQueryClass.class})am Anfang meiner Testklasse verwendet.

Aber wenn ich den Test debugge, ruft er immer noch die eigentliche Methode getNextId()der MyQueryClassKlasse auf.

Was vermisse ich hier? Kann mir jemand helfen, da ich neu bei Mockito und PowerMockito bin.

user3942446
quelle

Antworten:

218

Sie müssen die Klasse, in der der Konstruktor aufgerufen wird,@PrepareForTest anstelle der Klasse, die erstellt wird, in die Annotation einfügen - siehe Scheinkonstruktion neuer Objekte .

In deinem Fall:

@PrepareForTest(MyQueryClass.class)

@PrepareForTest(A.class)

Allgemeiner:

@PrepareForTest(NewInstanceClass.class)

@PrepareForTest(ClassThatCreatesTheNewInstance.class)

TrueDub
quelle
1
Vielen Dank. Es funktionierte jetzt, nachdem die aktuelle Klasse Eg A in den @PrepareForTest aufgenommen wurde.
user3942446
2
Ich verbringe auch eine Weile damit. Danke @TrueDub. Weil die Referenz veraltet ist. Ich aktualisiere es einfach. github.com/jayway/powermock/wiki/MockConstructor Es heißt: Verwenden Sie die Annotation @PrepareForTest (ClassThatCreatesTheNewInstance.class) auf Klassenebene des Testfalls.
Victor Choy
4
Ich habe das gleiche Problem, aber diese Lösung funktioniert nicht für mich
Dexter
3
Diese Lösung funktioniert einfach nicht, wenn Sie Eclemma für die Codeabdeckung verwenden. Das Hinzufügen der zu testenden Klasse zu @PrepareForTest führt zu einer Abdeckung von 0% für diese Klasse
ACV
2
Die Lösung wird funktionieren - der Test wird korrekt ausgeführt. Offensichtlich ist Eclemma nicht für PowerMockito gerüstet. Die Codeabdeckung ist nicht Teil dieser Frage.
TrueDub
3

Wie @TrueDub in seiner akzeptierten Antwort erwähnt hat, müssen Sie die Klasse hinzufügen, in der der Konstruktor aufgerufen wird @PrepareForTest.

Wenn Sie dies tun, ist die von Eclemma und Sonar gemeldete Abdeckung für diese Klasse für diese Klasse Null

Powermockito Wiki

Wir werden Javassist durch ByteBuddy (# 727) ersetzen und es sollte helfen, dieses alte Problem zu lösen. Derzeit gibt es jedoch KEINE MÖGLICHKEIT, PowerMock mit JaCoCo On-the-Fly-Instrumenten zu verwenden. Und keine Problemumgehung, um Codeabdeckung in IDE zu erhalten.

Die Lösung hier wäre also, den tatsächlichen Code umzugestalten, um eine statische Factory zu verwenden, die eine Instanz dieser Klasse zurückgibt und sie dann statisch verspottet.

ACV
quelle
Stimmen Sie Ihrem Kommentar zu.
Lathy
In Intellij ist das jedoch kein Problem.
ACV
0

Vielleicht können Sie einfach verwenden

Mockito.doReturn(value).when(xxx)
Jiajianchen
quelle