我写了一个工厂来产生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。是否有一个好的方法来模拟/验证这个特定的用例?


当前回答

观察:当您在静态实体中调用静态方法时,您需要更改@PrepareForTest中的类。

例如:

securityAlgo = MessageDigest.getInstance(SECURITY_ALGORITHM);

对于上面的代码,如果您需要模拟MessageDigest类,请使用

@PrepareForTest(MessageDigest.class)

而如果你有如下内容:

public class CustomObjectRule {

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

}

然后,您需要准备这个代码所在的类。

@PrepareForTest(CustomObjectRule.class)

然后模拟这个方法:

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

其他回答

要模拟静态方法,您应该使用Powermock查看: https://github.com/powermock/powermock/wiki/MockStatic。 Mockito不提供这种功能。

你可以读到一篇关于mockito的文章: http://refcardz.dzone.com/refcardz/mockito

对于那些使用JUnit 5的人来说,Powermock不是一个选项。您将需要以下依赖项来成功地使用Mockito模拟静态方法。

testCompile    group: 'org.mockito', name: 'mockito-core',           version: '3.6.0'
testCompile    group: 'org.mockito', name: 'mockito-junit-jupiter',  version: '3.6.0'
testCompile    group: 'org.mockito', name: 'mockito-inline',         version: '3.6.0'

mockito-junit-jupiter增加了对JUnit 5的支持。

对模拟静态方法的支持由模拟内联依赖项提供。

例子:

@Test
void returnUtilTest() {
    assertEquals("foo", UtilClass.staticMethod("foo"));

    try (MockedStatic<UtilClass> classMock = mockStatic(UtilClass.class)) {

        classMock.when(() -> UtilClass.staticMethod("foo")).thenReturn("bar");

        assertEquals("bar", UtilClass.staticMethod("foo"));
     }

     assertEquals("foo", UtilClass.staticMethod("foo"));
}

try-with-resource块用于使静态模拟保持临时状态,因此只在该范围内进行模拟。

当不使用try块时,一旦完成断言,请确保关闭mock。

MockedStatic<UtilClass> classMock = mockStatic(UtilClass.class)
classMock.when(() -> UtilClass.staticMethod("foo")).thenReturn("bar");
assertEquals("bar", UtilClass.staticMethod("foo"));
classMock.close();

模拟void方法:

在类上调用mockStatic时,该类中的所有静态void方法都会自动模拟为doNothing()。

观察:当您在静态实体中调用静态方法时,您需要更改@PrepareForTest中的类。

例如:

securityAlgo = MessageDigest.getInstance(SECURITY_ALGORITHM);

对于上面的代码,如果您需要模拟MessageDigest类,请使用

@PrepareForTest(MessageDigest.class)

而如果你有如下内容:

public class CustomObjectRule {

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

}

然后,您需要准备这个代码所在的类。

@PrepareForTest(CustomObjectRule.class)

然后模拟这个方法:

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

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

你的例子是:

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

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

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

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