我写了一个工厂来产生java.sql.Connection对象:

public class MySQLDatabaseConnectionFactory implements DatabaseConnectionFactory {

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

我想验证传递给DriverManager的参数。getConnection,但我不知道如何模拟静态方法。我的测试用例使用JUnit 4和Mockito。是否有一个好的方法来模拟/验证这个特定的用例?


当前回答

对于模仿静态函数,我能够这样做:

在helper类/对象中创建一个包装器函数。(使用名称变体可能有助于保持内容的分离和可维护。) 在代码中使用此包装器。(是的,代码的实现需要考虑到测试。) 模拟包装器函数。

包装器代码片段(不是真正的功能,只是为了说明)

class myWrapperClass ...
    def myWrapperFunction (...) {
        return theOriginalFunction (...)
    }

当然,在一个包装器类中积累多个这样的函数可能有利于代码重用。

其他回答

我还编写了Mockito和AspectJ的组合:https://github.com/iirekm/varia/tree/develop/ajmock

你的例子是:

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

我在《Mockito》中找到了一个解决方法。该特性仅在3.4.0版本中提供

https://asolntsev.github.io/en/2020/07/11/mockito-static-methods/

dependency In your build.gradle replace mockito-core:3.3.3 by mockito-inline:3.4.0: testImplementation('org.mockito:mockito-inline:3.4.0') what are we going to mock class Buddy { static String name() { return "John"; } } Mock the static method @Test void lookMomICanMockStaticMethods() { assertThat(Buddy.name()).isEqualTo("John"); try (MockedStatic<Buddy> theMock = Mockito.mockStatic(Buddy.class)) { theMock.when(Buddy::name).thenReturn("Rafael"); assertThat(Buddy.name()).isEqualTo("Rafael"); } assertThat(Buddy.name()).isEqualTo("John"); }

我想这对我们有帮助。

当您尝试模拟静态方法时,必须在try块中编写测试。因为重要的是要注意,作用域模拟必须由激活模拟的实体关闭。

      try (MockedStatic<Tester> tester = Mockito.mockStatic(Tester.class)) {
            tester.when(() -> Tester.testStatic("Testing..")).thenReturn(mock(ReturnObject.class));
    //Here you have to write the test cases
      }

在上面的例子中,我们必须模拟测试器类testStatic方法,输入参数为“Testing…”。在这里,该方法将返回一个ReturnObject类类型对象。因此我们写mockito当链像上面。

不要忘记在你的Gradle/maven中添加以下依赖项

    testImplementation 'org.mockito:mockito-inline:4.3.1'

如前所述,你不能用mockito模拟静态方法。

如果改变你的测试框架不是一个选择,你可以做以下事情:

为DriverManager创建一个接口,模拟这个接口,通过某种依赖注入注入它,并在这个模拟上进行验证。

你可以做一点重构:

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

然后你可以扩展你的MySQLDatabaseConnectionFactory类来返回一个模拟的连接,对参数进行断言等等。

扩展类可以驻留在测试用例中,如果它位于相同的包中(我鼓励您这样做)

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