By Naftuli Kay


2014-01-14 03:08:53 8 Comments

I've written a factory to produce java.sql.Connection objects:

public class MySQLDatabaseConnectionFactory implements DatabaseConnectionFactory {

    @Override public Connection getConnection() {
        try {
            return DriverManager.getConnection(...);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

I'd like to validate the parameters passed to DriverManager.getConnection, but I don't know how to mock a static method. I'm using JUnit 4 and Mockito for my test cases. Is there a good way to mock/verify this specific use-case?

10 comments

@MariuszS 2014-01-14 14:27:04

Use PowerMockito on top of Mockito.

Example code:

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

    @Test
    public void shouldVerifyParameters() throws Exception {

        //given
        PowerMockito.mockStatic(DriverManager.class);
        BDDMockito.given(DriverManager.getConnection(...)).willReturn(...);

        //when
        sut.execute(); // System Under Test (sut)

        //then
        PowerMockito.verifyStatic();
        DriverManager.getConnection(...);

    }

More information:

@Naftuli Kay 2014-01-16 00:07:21

While this works in theory, having a hard time in practice...

@Innokenty 2014-11-26 10:21:52

Unfortunately the huge disadvantage of this is the need for PowerMockRunner though.

@TejjD 2015-12-29 05:22:04

sut.execute() ? Means?

@MariuszS 2015-12-29 09:36:08

System Under Test, the class that requires mock of DriverManager. kaczanowscy.pl/tomek/2011-01/testing-basics-sut-and-docs

@sattu 2016-04-05 15:00:41

why does this line executes "DriverManager.getConnection(...)" method BDDMockito.given(DriverManager.getConnection(...)).willRetur‌​n(...);

@MariuszS 2016-04-07 16:51:51

@sattu This is recording behaviour (stub method calls). Instruction: When someone invoke this method, then return this.

@M2E67 2016-10-22 10:02:22

PowerMockito is so pretty solution but it not suitable for some cases, for example jacoco does not consider tests coverage which methods and classes have used PowerMockito

@MariuszS 2016-10-24 09:34:05

generally it is better to refactor and do not use static methods

@jakub.g 2017-09-27 09:56:00

Note that PowerMockito mocks/stubs all static methods of a class. So if you want to mock ClassA::methodY to test ClassA::methodX, it's not going to work well. In that case, ClassA::methodY has to be extracted to ClassB.

@EM-Creations 2017-10-26 12:47:49

FYI, if you're already using JUnit4 you can do @RunWith(PowerMockRunner.class) and below that @PowerMockRunnerDelegate(JUnit4.class).

@Zafer Celaloglu 2017-12-04 10:03:08

what about 2 static method in different classes?

@MariuszS 2017-12-04 11:02:26

@ZaferCelaloglu try to specify two classes inside @PrepareForTest

@Gellweiler 2018-03-28 18:51:47

I used powermock in the past and it's a good tool, but really you should use it with caution. It comes with a lot of quirks, which is no surprise considering how it works. Most times your just better off wrapping stuff in methods.

@eventhorizon 2018-05-24 13:52:50

And if your mocking target is used inside another class object instance, remeber to prepare the class in the @PrepareForTest annotation! :-)

@MariuszS 2019-04-09 16:33:01

@PhilipRego getConnection return void?

@MariuszS 2019-04-09 16:38:42

@PhilipRego this answer is not about your function, it is about function with the result. Read about stubbing void methods first: static.javadoc.io/org.mockito/mockito-core/2.26.0/org/mockit‌​o/…

@MariuszS 2019-04-09 19:26:04

@PhilipRego this is true that you cannot mix ArgumentMatchers and real objects. So stick to ArgumentMatchers for all parameters.

@Philip Rego 2019-04-09 19:44:20

@NoisyBoy 2019-04-18 19:20:06

Well this works fine but the problem now I'm facing is, other static method of my Util class are returning null & I don't know how to get those real methods to work without mocking them. I want those methods to run as they are, but since I've enabled powermocking on this whole class PowerMockito.mockStatic(DateTimeUtility.class); I am stuck with it

@iirekm 2017-11-01 17:46:19

I also wrote a combination of Mockito and AspectJ: https://github.com/iirekm/varia/tree/develop/ajmock

Your example becomes:

when(() -> DriverManager.getConnection(...)).thenReturn(...);

@Zlatan 2018-11-12 13:19:30

Use JMockit framework. It worked for me. You don't have to write statements for mocking DBConenction.getConnection() method. Just the below code is enough.

@Mock below is mockit.Mock package

Connection jdbcConnection = Mockito.mock(Connection.class);

MockUp<DBConnection> mockUp = new MockUp<DBConnection>() {

            DBConnection singleton = new DBConnection();

            @Mock
            public DBConnection getInstance() { 
                return singleton;
            }

            @Mock
            public Connection getConnection() {
                return jdbcConnection;
            }
         };

@David Miguel 2018-08-19 20:56:04

Mockito cannot capture static methods, but since Mockito 2.14.0 you can simulate it by creating invocation instances of static methods.

Example (extracted from their tests):

public class StaticMockingExperimentTest extends TestBase {

    Foo mock = Mockito.mock(Foo.class);
    MockHandler handler = Mockito.mockingDetails(mock).getMockHandler();
    Method staticMethod;
    InvocationFactory.RealMethodBehavior realMethod = new InvocationFactory.RealMethodBehavior() {
        @Override
        public Object call() throws Throwable {
            return null;
        }
    };

    @Before
    public void before() throws Throwable {
        staticMethod = Foo.class.getDeclaredMethod("staticMethod", String.class);
    }

    @Test
    public void verify_static_method() throws Throwable {
        //register staticMethod call on mock
        Invocation invocation = Mockito.framework().getInvocationFactory().createInvocation(mock, withSettings().build(Foo.class), staticMethod, realMethod,
                "some arg");
        handler.handle(invocation);

        //verify staticMethod on mock
        //Mockito cannot capture static methods so we will simulate this scenario in 3 steps:
        //1. Call standard 'verify' method. Internally, it will add verificationMode to the thread local state.
        //  Effectively, we indicate to Mockito that right now we are about to verify a method call on this mock.
        verify(mock);
        //2. Create the invocation instance using the new public API
        //  Mockito cannot capture static methods but we can create an invocation instance of that static invocation
        Invocation verification = Mockito.framework().getInvocationFactory().createInvocation(mock, withSettings().build(Foo.class), staticMethod, realMethod,
                "some arg");
        //3. Make Mockito handle the static method invocation
        //  Mockito will find verification mode in thread local state and will try verify the invocation
        handler.handle(verification);

        //verify zero times, method with different argument
        verify(mock, times(0));
        Invocation differentArg = Mockito.framework().getInvocationFactory().createInvocation(mock, withSettings().build(Foo.class), staticMethod, realMethod,
                "different arg");
        handler.handle(differentArg);
    }

    @Test
    public void stubbing_static_method() throws Throwable {
        //register staticMethod call on mock
        Invocation invocation = Mockito.framework().getInvocationFactory().createInvocation(mock, withSettings().build(Foo.class), staticMethod, realMethod,
                "foo");
        handler.handle(invocation);

        //register stubbing
        when(null).thenReturn("hey");

        //validate stubbed return value
        assertEquals("hey", handler.handle(invocation));
        assertEquals("hey", handler.handle(invocation));

        //default null value is returned if invoked with different argument
        Invocation differentArg = Mockito.framework().getInvocationFactory().createInvocation(mock, withSettings().build(Foo.class), staticMethod, realMethod,
                "different arg");
        assertEquals(null, handler.handle(differentArg));
    }

    static class Foo {

        private final String arg;

        public Foo(String arg) {
            this.arg = arg;
        }

        public static String staticMethod(String arg) {
            return "";
        }

        @Override
        public String toString() {
            return "foo:" + arg;
        }
    }
}

Their goal is not to directly support static mocking, but to improve its public APIs so that other libraries, like Powermockito, don't have to rely on internal APIs or directly have to duplicate some Mockito code. (source)

Disclaimer: Mockito team thinks that the road to hell is paved with static methods. However, Mockito's job is not to protect your code from static methods. If you don’t like your team doing static mocking, stop using Powermockito in your organization. Mockito needs to evolve as a toolkit with an opinionated vision on how Java tests should be written (e.g. don't mock statics!!!). However, Mockito is not dogmatic. We don't want to block unrecommended use cases like static mocking. It's just not our job.

@6324 2017-01-13 22:52:01

I had a similar issue. The accepted answer did not work for me, until I made the change: @PrepareForTest(TheClassThatContainsStaticMethod.class), according to PowerMock's documentation for mockStatic.

And I don't have to use BDDMockito.

My class:

public class SmokeRouteBuilder {
    public static String smokeMessageId() {
        try {
            return InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            log.error("Exception occurred while fetching localhost address", e);
            return UUID.randomUUID().toString();
        }
    }
}

My test class:

@RunWith(PowerMockRunner.class)
@PrepareForTest(SmokeRouteBuilder.class)
public class SmokeRouteBuilderTest {
    @Test
    public void testSmokeMessageId_exception() throws UnknownHostException {
        UUID id = UUID.randomUUID();

        mockStatic(InetAddress.class);
        mockStatic(UUID.class);
        when(InetAddress.getLocalHost()).thenThrow(UnknownHostException.class);
        when(UUID.randomUUID()).thenReturn(id);

        assertEquals(id.toString(), SmokeRouteBuilder.smokeMessageId());
    }
}

@Teddy 2019-02-11 10:53:08

Not able to figure out ?.mockStatic and ?.when currently with JUnit 4

@Teddy 2019-02-11 10:53:38

PowerMock.mockStatic & Mockito.when doesn't seem to work.

@some random guy 2017-10-30 18:55:58

Observation : When you call static method within a static entity, you need to change the class in @PrepareForTest.

For e.g. :

securityAlgo = MessageDigest.getInstance(SECURITY_ALGORITHM);

For the above code if you need to mock MessageDigest class, use

@PrepareForTest(MessageDigest.class)

While if you have something like below :

public class CustomObjectRule {

    object = DatatypeConverter.printHexBinary(MessageDigest.getInstance(SECURITY_ALGORITHM)
             .digest(message.getBytes(ENCODING)));

}

then, you'd need to prepare the class this code resides in.

@PrepareForTest(CustomObjectRule.class)

And then mock the method :

PowerMockito.mockStatic(MessageDigest.class);
PowerMockito.when(MessageDigest.getInstance(Mockito.anyString()))
      .thenThrow(new RuntimeException());

@SoftwareSavant 2018-07-06 01:06:04

I was banging my head against the wall trying to figure out why my static class wasn't mocking. You would think in all the tutorials on the interwebs, ONE would have gone into more than the bare-bones use case.

@99Sono 2015-04-24 07:57:44

The typical strategy for dodging static methods that you have no way of avoiding using, is by creating wrapped objects and using the wrapper objects instead.

The wrapper objects become facades to the real static classes, and you do not test those.

A wrapper object could be something like

public class Slf4jMdcWrapper {
    public static final Slf4jMdcWrapper SINGLETON = new Slf4jMdcWrapper();

    public String myApisToTheSaticMethodsInSlf4jMdcStaticUtilityClass() {
        return MDC.getWhateverIWant();
    }
}

Finally, your class under test can use this singleton object by, for example, having a default constructor for real life use:

public class SomeClassUnderTest {
    final Slf4jMdcWrapper myMockableObject;

    /** constructor used by CDI or whatever real life use case */
    public myClassUnderTestContructor() {
        this.myMockableObject = Slf4jMdcWrapper.SINGLETON;
    }

    /** constructor used in tests*/
    myClassUnderTestContructor(Slf4jMdcWrapper myMock) {
        this.myMockableObject = myMock;
    }
}

And here you have a class that can easily be tested, because you do not directly use a class with static methods.

If you are using CDI and can make use of the @Inject annotation then it is even easier. Just make your Wrapper bean @ApplicationScoped, get that thing injected as a collaborator (you do not even need messy constructors for testing), and go on with the mocking.

@aro_tech 2016-10-14 21:45:05

I created a tool to automatically generate Java 8 "mixin" interfaces which wrap static calls: github.com/aro-tech/interface-it The generated mixins can be mocked like any other interface, or if your class under test "implements" the interface you can override any of its methods in a subclass for the test.

@marek.kapowicki 2014-01-14 10:49:01

To mock static method you should use a Powermock look at: https://github.com/powermock/powermock/wiki/MockStatic. Mockito doesn't provide this functionality.

You can read nice a article about mockito: http://refcardz.dzone.com/refcardz/mockito

@the_new_mr 2018-07-23 11:01:24

Please don't link to a website. Answers should include actual usable answers. If the site goes down or changes, the answer is no longer valid.

@Fermin Silva 2015-08-12 21:35:33

You can do it with a little bit of refactoring:

public class MySQLDatabaseConnectionFactory implements DatabaseConnectionFactory {

    @Override public Connection getConnection() {
        try {
            return _getConnection(...some params...);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    //method to forward parameters, enabling mocking, extension, etc
    Connection _getConnection(...some params...) throws SQLException {
        return DriverManager.getConnection(...some params...);
    }
}

Then you can extend your class MySQLDatabaseConnectionFactory to return a mocked connection, do assertions on the parameters, etc.

The extended class can reside within the test case, if it's located in the same package (which I encourage you to do)

public class MockedConnectionFactory extends MySQLDatabaseConnectionFactory {

    Connection _getConnection(...some params...) throws SQLException {
        if (some param != something) throw new InvalidParameterException();

        //consider mocking some methods with when(yourMock.something()).thenReturn(value)
        return Mockito.mock(Connection.class);
    }
}

@ChrisM 2014-01-14 13:29:03

As mentioned before you can not mock static methods with mockito.

If changing your testing framework is not an option you can do the following:

Create an interface for DriverManager, mock this interface, inject it via some kind of dependency injection and verify on that mock.

Related Questions

Sponsored Content

50 Answered Questions

5 Answered Questions

[SOLVED] Use Mockito to mock some methods but not others

  • 2013-02-20 00:59:08
  • Victor Grazi
  • 337087 View
  • 328 Score
  • 5 Answer
  • Tags:   java mocking mockito

26 Answered Questions

[SOLVED] Java inner class and static nested class

11 Answered Questions

[SOLVED] Difference between @Mock and @InjectMocks

9 Answered Questions

[SOLVED] How to make mock to void methods with Mockito

2 Answered Questions

[SOLVED] Mockito test a void method throws an exception

8 Answered Questions

[SOLVED] What is Mocking?

  • 2010-04-19 07:33:21
  • masoud ramezani
  • 197728 View
  • 471 Score
  • 8 Answer
  • Tags:   unit-testing mocking

5 Answered Questions

[SOLVED] Can Mockito capture arguments of a method called multiple times?

3 Answered Questions

[SOLVED] Can Mockito stub a method without regard to the argument?

1 Answered Questions

[SOLVED] Mocking static methods with PowerMock and Mockito

Sponsored Content