1

I'm trying to mockStatic DriverManager.class and get mockConnection but a real static void method is called getConnection instead.

Tests class:

@RunWith(PowerMockRunner.class)
@PrepareForTest(DriverManager.class)
public class MyClassTest {

  @Before
  public void setUp() throws Exception {
    Connection connection = mock(Connection.class);
    Statement statement = mock(Statement.class);

    PowerMockito.mockStatic(DriverManager.class);
    PowerMockito.doReturn(connection).when(DriverManager.class, "getConnection", anyString(), anyString(), anyString());
  }

  @Test
  public void testMain() {
    // arrange
    String[] args = {"name", "password", "database"};
  }
}

Pom.xml

  <properties>
    <powermock.version>1.7.4</powermock.version>
  </properties>
  <dependencies>
    <!-- https://mvnrepository.com/artifact/junit/junit -->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.powermock</groupId>
      <artifactId>powermock-module-junit4</artifactId>
      <version>${powermock.version}</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.powermock</groupId>
      <artifactId>powermock-api-mockito2</artifactId>
      <version>${powermock.version}</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

Exception which I got when trying to execute PowerMockito.doReturn(connection).when(DriverManager.class, "getConnection", anyString(), anyString(), anyString()):

java.sql.SQLException: No suitable driver found for 
at java.sql.DriverManager.getConnection(DriverManager.java:689)
at java.sql.DriverManager.getConnection(DriverManager.java:247)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.powermock.reflect.internal.WhiteboxImpl.performMethodInvocation(WhiteboxImpl.java:1846)
at org.powermock.reflect.internal.WhiteboxImpl.doInvokeMethod(WhiteboxImpl.java:810)
at org.powermock.reflect.internal.WhiteboxImpl.invokeMethod(WhiteboxImpl.java:790)
at org.powermock.reflect.Whitebox.invokeMethod(Whitebox.java:466)
at org.powermock.api.mockito.internal.expectation.PowerMockitoStubberImpl.when(PowerMockitoStubberImpl.java:110)
at vez.MyClassTest.setUp(MyClassTest.java:26)

What did I wrong? How to properly mock the DriverManager.class? PS. When I look into the org.powermock.api.mockito.internal.expectation.PowerMockitoStubberImpl.when(PowerMockitoStubberImpl.java:110) I see that it always invoke "Whitebox.invokeMethod(classMock, methodToExpect, parameters);" Therefore I don't understand how it works in general.

vzateychuk
  • 301
  • 1
  • 3
  • 12

2 Answers2

3

The DriverManager class will attempt to load the driver classes referenced in the "jdbc.drivers" system property as part of its initialization. This happens when the DriverManager class is loaded, i.e., even before any method like getConnection() is invoked. So its not that the exception you are getting is because a real getConnection() is getting called. Its because you have not included a real driver class on the classpath, as is evident from your pom, that DriverManager can load during its initialization. So, include a driver in your pom and then try.

Please see https://docs.oracle.com/javase/7/docs/api/java/sql/DriverManager.html and the static block in the source code of DriverManager class at https://github.com/JetBrains/jdk8u_jdk/blob/master/src/share/classes/java/sql/DriverManager.java.

Sanjeev Sachdev
  • 1,241
  • 1
  • 15
  • 23
  • ok, I've added missed dependency, and rewrited setupMock like this: PowerMockito.mockStatic(DriverManager.class); PowerMockito.when(DriverManager.getConnection(anyString(), anyString(), anyString())).thenReturn(conn); But there is new exception "java.lang.LinkageError: loader constraint violation: loader (instance of org/powermock/core/classloader/MockClassLoader) previously initiated loading for a different type" when I'm trying to run DriverManager.registerDriver(new oracle.jdbc.OracleDriver()); Looks like the DriverManager is not been mocked at all. Have you any ideas? – vzateychuk Jul 13 '18 at 20:58
  • Both the DriverManager and Drivers to be registered should be loaded by the same classloader. In your case, DriverManager was loaded by MockClassLoader and the Driver oracle.jdbc.OracleDriver by JVM's own classloader. Why have you included the statement DriverManager.registerDriver(new oracle.jdbc.OracleDriver() ? Do you really want to programatically load the Oracle driver? DriverManager.registerDriver() is usually called by the Drivers themselves when they are newly loaded. See https://docs.oracle.com/javase/7/docs/api/java/sql/DriverManager.html#registerDriver(java.sql.Driver). – Sanjeev Sachdev Jul 14 '18 at 06:22
  • Thank you, Sanjeev, it's clear now. Regarding your question "Why have you included the statement DriverManager.registerDriver(new oracle.jdbc.OracleDriver()": Unfortunately it's not my code, it is hardcoded in the class for which I need to create unit test. – vzateychuk Jul 14 '18 at 18:31
1

The solution which works eventually when I create instance of the objectUnderTest and put its class name under @PrepareForTest annotation (disregard of warnings in the out console). Though I have no idea why it works this way:

@RunWith(PowerMockRunner.class)
@PrepareForTest(DriverManager.class, MyClass.class)
public class MyClassTest {

  @Before
  public void setUp() throws Exception {
    Connection connection = mock(Connection.class);
    Statement statement = mock(Statement.class);

    PowerMockito.mockStatic(DriverManager.class);
    PowerMockito.when(DriverManager.getConnection(anyString(), anyString(), anyString())).thenReturn(connection);
  }

  @Test
  public void testMain() {
    // arrange
    String[] args = {"name", "password", "database"};
    MyClass myClass = new MyClass();
    myClass.method();
    ...
  }
vzateychuk
  • 301
  • 1
  • 3
  • 12