mock method compatible and java unit-testing junit mockito powermock

java - method - powermock maven



Métodos estáticos de burla con PowerMock y Mockito (1)

Estoy intentando verificar una llamada a java.sql.DriverManager.getConnection utilizando JUnit, Mockito y PowerMock.

Aquí está mi caso de prueba:

@RunWith(PowerMockRunner.class) @PrepareForTest(DriverManager.class) public class MySQLDatabaseConnectionFactoryTest { private ConfigurationService configurationService; private MySQLDatabaseConnectionFactory reference; @Before public void setUp() throws Exception { this.reference = new MySQLDatabaseConnectionFactory(); } @Test public void testGetConnection() throws SQLException { // setup Connection connection = mock(Connection.class); PowerMockito.mockStatic(DriverManager.class); when(DriverManager.getConnection(anyString(), anyString(), anyString())).thenReturn(connection); // run this.reference.getConnection(); // verify PowerMockito.verifyStatic(); DriverManager.getConnection("jdbc:mysql://myhost:1111/database", "username", "password"); } }

Aquí está el código bajo prueba:

public class MySQLDatabaseConnectionFactory implements DatabaseConnectionFactory { @Override public Connection getConnection(IApplicationInstance appInstance) { try { return DriverManager.getConnection(String.format("jdbc:mysql://%s:%d/%s", MYSQL_HOST, MYSQL_PORT, MYSQL_DATABASE), MYSQL_USERNAME, MYSQL_PASSWORD); } catch (SQLException e) { throw new RuntimeException(e); } } }

Curiosamente, este código falla con una java.sql.SQLException :

java.lang.RuntimeException: java.sql.SQLException: No suitable driver found for jdbc:mysql://myhost:1111/database

Ahora, puedo asegurarme fácilmente de que mi controlador SQL (MySQL en este caso) está cargado en el momento de la prueba, pero ¿por qué no está completamente burlado el método estático sin efectos secundarios?

Actualizar:

Mejor he aislado el problema. He agregado un método de prueba a mi caso de prueba que intenta obtener una conexión de DriverManager :

@Test public void testSomething() { Connection conn = mock(Connection.class); mockStatic(DriverManager.class); when(DriverManager.getConnection(anyString())).thenReturn(conn); Connection c = DriverManager.getConnection("whut"); verifyStatic(); DriverManager.getConnection("whut"); }

Esta prueba realmente pasa, mientras que la otra prueba todavía falla. Parece que PowerMock no se está burlando de la referencia a la clase dentro de MySQLDatabaseConnectionFactory . ¿Cómo puedo solucionar esto?


Cambiar su valor de anotación @PrepareForTest a MySQLDatabaseConnectionFactory.class resolverá este problema.

Esta anotación le dice a PowerMock que prepare ciertas clases para la prueba. Las clases que deben definirse mediante esta anotación son, por lo general, aquellas que deben manipularse mediante códigos de bytes. Esto incluye clases finales, clases con final, privadas, estáticas.

En esta situación, PowerMockito debe reemplazar la invocación al método estático DriverManager.getConnection con código simulado. Esto se hace con el uso de la manipulación de byte-code.

Codigo completo

@RunWith(PowerMockRunner.class) @PrepareForTest(MySQLDatabaseConnectionFactory.class) public class MySQLDatabaseConnectionFactoryTest { private MySQLDatabaseConnectionFactory reference; @Before public void setUp() throws Exception { reference = new MySQLDatabaseConnectionFactory(); } @Test public void testGetConnection() throws SQLException { // given PowerMockito.mockStatic(DriverManager.class); BDDMockito.given(DriverManager.getConnection(anyString(), anyString(), anyString())) .willReturn(mock(Connection.class)); // when reference.getConnection(); // then PowerMockito.verifyStatic(); DriverManager.getConnection("jdbc:mysql://myhost:1111/database", "username", "password"); } }

¡Gracias a @Szpak por ayudarme a resolver este problema!