用Mockito模拟静态方法

2022-07-21 09:26:32

本文翻译自:Mocking static methods with Mockito

I've written a factory to producejava.sql.Connection objects:我已经写了一个工厂来产生java.sql.Connection对象:

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 toDriverManager.getConnection , but I don't know how to mock a static method.我想验证传递给DriverManager.getConnection的参数,但是我不知道如何模拟静态方法。I'm using JUnit 4 and Mockito for my test cases.我在测试用例中使用的是JUnit 4和Mockito。Is there a good way to mock/verify this specific use-case?有没有模拟/验证此特定用例的好方法?


#1楼

参考:https://stackoom.com/question/1QYTj/用Mockito模拟静态方法


#2楼

To mock static method you should use a Powermock look at:https://github.com/powermock/powermock/wiki/MockStatic .要模拟静态方法,您应该使用Powermock来查看:https ://github.com/powermock/powermock/wiki/MockStaticMockitodoesn't provide this functionality.Mockito不提供此功能。

You can read nice a article about mockito:http://refcardz.dzone.com/refcardz/mockito您可以阅读有关Mockito的不错的文章:http: //refcardz.dzone.com/refcardz/mockito


#3楼

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.为DriverManager创建一个接口,模拟该接口,通过某种依赖注入将其注入,并在该模拟上进行验证。


#4楼

UsePowerMockito on top of Mockito.在Mockito上使用PowerMockito

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:更多信息:


#5楼

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.如果您使用的是CDI,并且可以使用@Inject批注,那么它会更加容易。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.只需使您的包装器bean @ApplicationScoped,以协作者的身份注入该对象(您甚至不需要杂乱的构造函数进行测试),然后继续进行模拟即可。


#6楼

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 classMySQLDatabaseConnectionFactory to return a mocked connection, do assertions on the parameters, etc.然后,您可以扩展类MySQLDatabaseConnectionFactory以返回模拟的连接,对参数进行断言等。

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);
    }
}
  • 作者:CHCH998
  • 原文链接:https://blog.csdn.net/CHCH998/article/details/106874736
    更新时间:2022-07-21 09:26:32