我写了一个工厂来产生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());
从Mockito 3.4.0开始,就可以在Mockito中模拟静态方法。
详情见:
https://github.com/mockito/mockito/releases/tag/v3.4.0
https://github.com/mockito/mockito/issues/1013
https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#static_mocks
assertEquals("foo", Foo.method());
try (MockedStatic mocked = mockStatic(Foo.class)) {
mocked.when(Foo::method).thenReturn("bar");
assertEquals("bar", Foo.method());
mocked.verify(Foo::method);
}
assertEquals("foo", Foo.method());
在你的例子中,是这样的:
@Test
public void testStaticMockWithVerification() throws SQLException {
try (MockedStatic<DriverManager> dummy = Mockito.mockStatic(DriverManager.class)) {
DatabaseConnectionFactory factory = new MySQLDatabaseConnectionFactory();
dummy.when(() -> DriverManager.getConnection("arg1", "arg2", "arg3"))
.thenReturn(new Connection() {/*...*/});
factory.getConnection();
dummy.verify(() -> DriverManager.getConnection(eq("arg1"), eq("arg2"), eq("arg3")));
}
}
注意:模拟STATIC METHODS需要模拟内联依赖而不是模拟核心。
对于JUnit5也添加这个:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>