El uso de PowerMockito.whenNew () no se está burlando y se llama al método original

100

Tengo un código similar a este a continuación:

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

Ahora estoy escribiendo una prueba para A.myMethod(someargs). Quiero omitir el método real query.getNextId()y, en su lugar, devolver un valor de código auxiliar. Básicamente, quiero burlarme MyQueryClass.

Entonces, en mi caso de prueba, he usado:

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

Usé @RunWith(PowerMockRunner.class)y @PrepareForTest({MyQueryClass.class})al comienzo de mi clase de prueba.

Pero cuando depuro la prueba, sigue llamando al método real getNextId()de la MyQueryClassclase.

¿Que me estoy perdiendo aqui? ¿Alguien puede ayudarme ya que soy nuevo en Mockito y PowerMockito?

user3942446
fuente

Respuestas:

220

Debe colocar la clase donde se llama al constructor en la @PrepareForTestanotación en lugar de la clase que se está construyendo; consulte Construcción simulada de nuevos objetos .

En tu caso:

@PrepareForTest(MyQueryClass.class)

@PrepareForTest(A.class)

Mas general:

@PrepareForTest(NewInstanceClass.class)

@PrepareForTest(ClassThatCreatesTheNewInstance.class)

TrueDub
fuente
1
Muchas gracias. Funcionó ahora después de incluir la clase actual Eg A en el @PrepareForTest.
user3942446
2
También dedico un tiempo a esto. Gracias @TrueDub. Porque la referencia está desactualizada. Solo lo actualizo. github.com/jayway/powermock/wiki/MockConstructor Dice: Use la anotación @PrepareForTest (ClassThatCreatesTheNewInstance.class) en el nivel de clase del caso de prueba.
Victor Choy
4
Tengo el mismo problema, pero esta solución no me funciona
dexter
3
Esta solución simplemente no funcionará si está utilizando eclemma para la cobertura del código. Agregar la clase bajo prueba a @PrepareForTest resultará en una cobertura del 0% para esa clase
ACV
2
La solución funcionará: la prueba se ejecuta correctamente. Obviamente, eclemma no está equipado para lidiar con PowerMockito. La cobertura del código no forma parte de esta pregunta.
TrueDub
3

Como @TrueDub mencionó en su respuesta aceptada, debe agregar la clase donde se llama al constructor al @PrepareForTest.

Sin embargo, si hace esto, la cobertura para esa clase según lo informado por eclemma y Sonar será cero para esa clase

Wiki bajoterra

Vamos a reemplazar Javassist con ByteBuddy (# 727) y debería ayudar a resolver este viejo problema. Pero ahora mismo NO HAY MANERA DE USAR PowerMock con instrumentación sobre la marcha de JaCoCo. Y no hay solución para obtener cobertura de código en IDE.

Entonces, la solución aquí sería refactorizar el código real para usar una fábrica estática que devolvería una instancia de esa clase y luego simularla estáticamente.

ACV
fuente
Estoy de acuerdo con tu comentario.
Lathy
Sin embargo, eso no es un problema en Intellij.
ACV
0

Quizás puedas simplemente usar

Mockito.doReturn(value).when(xxx)
jiajianchen
fuente