power mockito2 mock method compatible and powermock

mockito2 - powermock junit 5



PowerMock: se burla de la variable final estática privada, un ejemplo concreto (1)

¿Cuál es la burla mínima absoluta que se debe hacer para pasar esta prueba?

código:

class PrivateStaticFinal { private static final Integer variable = 0; public static Integer method() { return variable + 1; } }

prueba:

@RunWith(PowerMockRunner.class) @PrepareForTest(PrivateStaticFinal.class) class PrivateStaticFinalTest { @Test public void testMethod() { //TODO PrivateStaticFinal.variable = 100 assertEquals(PrivateStaticFinal.method(), 101); } }

relacionado: simulacro de variables finales estáticas privadas en la clase de prueba (no hay una respuesta clara)


Descargo de responsabilidad: Después de mucha búsqueda en varios hilos, he encontrado una respuesta. Se puede hacer, pero el consenso general es que no es muy seguro, pero como usted lo hace SOLO EN LAS PRUEBAS DE UNIDAD, creo que acepta esos riesgos :)

La respuesta no es burlarse, ya que la mayoría de los burlones no te permiten piratear una final. La respuesta es un poco más "hacky", donde en realidad está modificando el campo privado cuando Java está llamando a las clases java.lang.reflect.Field y java.lang.reflect.Modifier (reflexión). Mirando esta respuesta , pude juntar el resto de tu prueba, sin la necesidad de burlarte para resolver tu problema.

El problema con esa respuesta es que estaba ejecutando la NoSuchFieldException al intentar modificar la variable . La ayuda para eso estaba en otra publicación sobre cómo acceder a un campo que era privado y no público.

Reflexión / Manipulación de Campo Explicado:

Ya que Mocking no puede manejar el final, en vez de eso, lo que terminamos haciendo es hackear la raíz del propio campo. Cuando usamos las manipulaciones de Field (reflexión), buscamos la variable específica dentro de una clase / objeto. Una vez que Java lo encuentra, obtenemos los "modificadores" de la misma, que le dicen a la variable qué restricciones / reglas tiene como final , static , private , public , etc. Encontramos la variable correcta, y luego le decimos al código que está disponible para que Nos permite cambiar estos modificadores. Una vez que hemos cambiado el "acceso" en la raíz para permitirnos manipularlo, estamos desactivando la parte "final" de él. Entonces podemos cambiar el valor y establecerlo en lo que necesitemos.

En pocas palabras, estamos modificando la variable para permitirnos cambiar sus propiedades, eliminando la propiedad de final , y luego cambiando el valor ya que ya no es final . Para obtener más información sobre esto, echa un vistazo a la publicación de donde surgió la idea .

Así que paso a paso pasamos la variable que queremos manipular y ...

// Mark the field as public so we can toy with it field.setAccessible(true); // Get the Modifiers for the Fields Field modifiersField = Field.class.getDeclaredField("modifiers"); // Allow us to change the modifiers modifiersField.setAccessible(true); // Remove final modifier from field by blanking out the bit that says "FINAL" in the Modifiers modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); // Set new value field.set(null, newValue);

Combinando todo esto en una nueva SUPER RESPUESTA obtendrás.

@RunWith(PowerMockRunner.class) @PrepareForTest() class PrivateStaticFinalTest { @Test public void testMethod(){ try { setFinalStatic(PrivateStaticFinal.class.getDeclaredField("variable"), Integer.valueOf(100)); } catch (SecurityException e) {fail();} catch (NoSuchFieldException e) {fail();} catch (Exception e) {fail();} assertEquals(PrivateStaticFinal.method(), Integer.valueOf(101)); } static void setFinalStatic(Field field, Object newValue) throws Exception { field.setAccessible(true); // remove final modifier from field Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); field.set(null, newValue); } }

Actualización La solución anterior solo funcionará para aquellas constantes que se inicializan en un bloque estático. Al declarar e inicializar la constante al mismo tiempo, puede suceder que el compilador la alinee, en cuyo momento se ignora cualquier cambio en el valor original.