Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mocking static methods with Mockito

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?

like image 829
Naftuli Kay Avatar asked Jan 14 '14 03:01

Naftuli Kay


People also ask

Can we mock static methods in Mockito?

Since static method belongs to the class, there is no way in Mockito to mock static methods.

How do you mock a private static method?

For Mockito, there is no direct support to mock private and static methods. In order to test private methods, you will need to refactor the code to change the access to protected (or package) and you will have to avoid static/final methods.

Can static classes be mocked?

Because there is no instance variable, the class name itself should be used to access the members of a static class. The powerful capabilities of the feature-rich JustMock framework allow you to mock static classes and calls to static members like methods and properties, set expectations and verify results.


2 Answers

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:

  • Why doesn't Mockito mock static methods?
like image 124
MariuszS Avatar answered Oct 01 '22 04:10

MariuszS


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.

like image 41
99Sono Avatar answered Oct 01 '22 06:10

99Sono