使用 Powermockito 模拟 ClassLoader.getSystemClassLoader().loadClass

Mock ClassLoader.getSystemClassLoader().loadClass with Powermockito

我正在尝试测试实用程序方法,该方法检查特定 class 是否在 class 路径上,如果是 return true 否则 return false.

我为什么这样做:我必须独立 classes 扩展相同的 class,并且只有其中一个会在 classpath 上。如果 classpath.

上有一个特定的,则需要做特定的事情

使用下面的方法检查特定 class 是否在 class 路径上。 此检查只会在第一次请求后进行一次。 我也检查了 Class.forName() 但决定采用以下方法。

我的实用程序方法如下所示:

public static boolean isMyClassOnClassPath() {
    try {
        ClassLoader.getSystemClassLoader().loadClass("com.MyClass");
        return true;
    } catch (ClassNotFoundException ex) {
        return false;
    }

}

检查 false 条件很容易,因为特定 class 不是 ClassPath。 当此方法将 return true.

时,我正在尝试为积极的情况编写 Junit
@Test
public void isMyClassOnClassPathShouldReturnTrueWhenMyClassIsOnClassPath() throws Exception{
    PowerMockito.mockStatic(MyClass.class);
    ClassLoader classLoader = PowerMockito.mock(ClassLoader.class);
    PowerMockito.mockStatic(ClassLoader.class);
    PowerMockito.when(ClassLoader.getSystemClassLoader()).thenReturn(classLoader);

    //trying to mock classLoader.loadClass, below way is incorrect
    //PowerMockito.when(classLoader.loadClass("com.MyClass")).thenReturn(Class<java.lang.Object.class>);
    Assert.assertTrue(MyClassUtil.isMyClassOnClassPath());
}

那么可以模拟 classLoader.loadClass() 方法吗?

老实说:甚至 做那样的事情。

简而言之,你就像一个坐在树上的人,开始砍掉那个人坐着的树的随机树枝。含义:这是 JVM 的核心部分。假设您的模拟有效:那么 每个 该方法的调用者都会收到您的模拟加载器!因此,当您的测试用例本身想要加载一些 类 时,它会 运行 到您的模拟中!

几乎和往常一样,当人们声称 "I need to user Powermock for xyz" 您的真正问题是另一个问题:您创建了无法测试的代码。通过在那里进行静态调用,您可以防止自己测试代码!

对于初学者,您可以看看 here 以了解如何编写可测试的代码。但如果您对如何修复您的设计感到好奇:

class ClassPathChecker {
  private final ClassLoader classLoader;
  ClassPathChecker() { this(ClassLoader.getSystemClassLoader()); }
  ClassPathChecker(ClassLoader classLoader) {
   this.classLoader = this.classLoader);
  }

  boolean canClassBeLoaded(String className) {
    try {
      classLoader.loadClass ...

上面使用依赖注入插入一个mocked ClassLoader;这使您可以完全 控制正在发生的一切。完全不使用 Powermock .

并且出于好奇:为什么您将自己限制在系统类加载器中?像 Class.forName("yourclass") 这样的简单调用不会告诉您相同的信息吗?