es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Los miembros externos estáticos burlados son nulos al probar una clase interna estática con PowerMockito.

Tengo una clase que se ve así:

public class OuterClass {
    protected static Server s;

<pre><code>public static class CrazyEvent implements Runnable {

    @Override
    public void run() {
        s.getSystemInfo();
    }
}
</code></pre>

<p>}

Tiene un miembro estático “s” de tipo Server, y una clase interna estática llamada CrazyEvent que extrae información del Server.

Estoy intentando probar este método run() en PowerMockito:

@RunWith(PowerMockRunner.class)
@PrepareForTest(OuterClass.class)
public class StaticInnerClassTest {
    private static class ServerMock extends Server {</p>

<pre><code>    protected ServerMock(ServerConfig sc) {
        super(sc);
    }

    @Override
    public void start() {

    }
}

private static class ServerConfigMock extends ServerConfig {

}

@Mock
ServerMock s = new ServerMock(new ServerConfigMock());

@Mock
UserMan um;

@InjectMocks
OuterClass.CrazyEvent ce = new OuterClass.CrazyEvent();

@Before
public void setUp() {

    MockitoAnnotations.initMocks(this);
    when(s.getUserMan()).thenReturn(um);

}

@Test
public void testInnerClass() {
    ce.run();
}
</code></pre>

<p>}

Recorramos el código:
Estoy extendiendo el objeto Server real con ServerMock para poder anular un método molesto que se llama en el constructor. Mi objeto Server simulado es “s”. Idealmente, me gustaría inyectar esta simulación en la clase interna estática anidada porque debe usarla.

El problema es que, cuando llamo a ce.run(), “s” es nulo y la simulación no se inyecta correctamente. Soy bastante nuevo en PowerMockito y he estado luchando para encontrar información en SO sobre este caso en particular.

Edit:
Hay un logger de slf4j privado y estático en la clase externa que es nulo cuando se llama desde el método run() en la clase interna. No sé cómo instanciarlo. Intenté extender la clase externa y hacer que el logger sea protegido e instanciarlo de esa manera, pero sin suerte.

No importa. Accidentalmente dejé una llamada a PowerMockito.mockStatic() que estaba rompiendo todo.

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Solución

    El problema al que se enfrenta el autor es que el objeto simulado s no se inyecta correctamente en la clase interna estática anidada CrazyEvent, lo que hace que sea nulo cuando se llama al método run(). Para inyectar correctamente el objeto simulado, el autor puede utilizar la anotación @PrepareForTest junto con el método PowerMockito.whenNew() para simular la creación del objeto CrazyEvent e inyectar el objeto simulado s.

    Aquí tienes una versión actualizada del código de prueba:

    @RunWith(PowerMockRunner.class)
    @PrepareForTest({OuterClass.class, OuterClass.CrazyEvent.class})
    public class StaticInnerClassTest {
        private static class ServerMock extends Server {
    
            protected ServerMock(ServerConfig sc) {
                super(sc);
            }
    
            @Override
            public void start() {
    
            }
        }
    
        private static class ServerConfigMock extends ServerConfig {
    
        }
    
        @Mock
        ServerMock s = new ServerMock(new ServerConfigMock());
    
        @Mock
        UserMan um;
    
        @Before
        public void setUp() {
            MockitoAnnotations.initMocks(this);
            when(s.getUserMan()).thenReturn(um);
        }
    
        @Test
        public void testInnerClass() throws Exception {
            // Simular la creación del objeto CrazyEvent
            PowerMockito.whenNew(OuterClass.CrazyEvent.class).withNoArguments().thenReturn(new OuterClass.CrazyEvent());
            // Llamar al método run() del objeto CrazyEvent simulado
            new OuterClass.CrazyEvent().run();
            // Añadir cualquier aserción o verificación necesaria
        }
    }
    

    La anotación @PrepareForTest se utiliza para indicar a PowerMockito que prepare la clase externa OuterClass, así como la clase interna estática anidada CrazyEvent para la prueba. Esto permite que el objeto simulado s se inyecte correctamente en CrazyEvent.

    A continuación, se utiliza el método PowerMockito.whenNew() para simular la creación de un nuevo objeto CrazyEvent y devolver un objeto simulado s cuando se llama a s.getSystemInfo() en el método run(). Por último, se llama al método run() del objeto CrazyEvent simulado y se pueden añadir cualquier aserción o verificación necesaria.

    Con estos cambios, el autor debería poder probar correctamente el método run() de la clase interna estática anidada CrazyEvent.

Comments are closed.