vzateychuk
vzateychuk

Reputation: 301

SQLException: 'No suitable driver found' when PowerMockito mockStatic DriverManager.class

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.

Upvotes: 1

Views: 1776

Answers (2)

vzateychuk
vzateychuk

Reputation: 301

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();
    ...
  }

Upvotes: 1

Sanjeev Sachdev
Sanjeev Sachdev

Reputation: 1321

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.

Upvotes: 3

Related Questions