【问题标题】:JUnit & Powermock: Native Library already loaded in another classloaderJUnit & Powermock:本机库已经加载到另一个类加载器中
【发布时间】:2016-08-31 11:25:56
【问题描述】:

我有一些测试类需要验证是否调用了 GLFW 函数。但是当我想在 IntelliJ 中执行所有测试时,我得到了错误:

Native Library lwjgl.dll already loaded in another classloader

我使用 Powermock 来验证静态方法是否已被调用:

@RunWith(PowerMockRunner.class)
@PrepareForTest({GLFW.class})
public class GlfwWindowImplTest {
    // ...
    @Test
    public void update_swapsBufferAndPollsEvents() {
        GlfwWindowImpl target = new GlfwWindowImpl(1L);
        mockStatic(GLFW.class);

        target.update();

        verifyStatic();
        GLFW.glfwSwapBuffers(1L);
        verifyStatic();
        GLFW.glfwPollEvents();
    }
}

@RunWith(PowerMockRunner.class)
@PrepareForTest({GLFW.class})
public class GlfwWindowSystemImplTest {
    // ...
    @Test(expected = GlfwInitializeException.class)
    public void initialize_throwsExceptionIfGlfwInitFails() {
        GlfwWindowSystemImpl target = new GlfwWindowSystemImpl();
        mockStatic(GLFW.class);
        when(GLFW.glfwInit()).thenReturn(GL_FALSE);

        target.initialize();
    }
}

【问题讨论】:

  • @PrepareForTest({GLFW.class}) 修改类并将其加载到新的类加载器中。
  • @Exhauzt 你有没有找到解决这个问题的方法?我不明白下面的解决方案告诉你做什么。您的原始代码似乎已经有 @PrepareForTest({GLFW.class})... 那么您有什么不同的做法呢?谢谢
  • 不,我实际上没有找到解决方案,但不久之后我不得不做另一个项目......所以我没有在这个主题上挖掘太多来找到解决方案。我也不明白那个解决方案

标签: java intellij-idea dll junit powermock


【解决方案1】:

回答这个帖子可能有点晚了,但我遇到了类似的问题,我能够用 PowerMock 解决它。 PowerMock 有 @SuppressStaticInitializationFor 可以帮助您克服这个问题。下面链接中的 Suppress static initializer 部分有一个很好的例子来说明如何做到这一点:

https://github.com/powermock/powermock/wiki/Suppress-Unwanted-Behavior

基本上,在您的情况下,可能有一个类正在调用 System.loadLibrary("lwjgl")。你需要找到那个类。示例:

public class SomeClass {
    ...
    static {
        System.loadLibrary ("lwjgl");
    }
    ...
}

然后在您的测试类中使用 @SuppressStaticInitializationFor 和类的完全限定名称:

@SuppressStaticInitializationFor("com.example.SomeClass")

如果执行 loadLibrary 调用的类是内部类,则需要添加 $InnerClass 以完全限定内部类。示例:

public class SomeClass {
    ...
    public static class SomeInnerClass {
        static {
            System.loadLibrary ("lwjgl");
        }
    }
    ...
}

那么你需要使用:

@SuppressStaticInitializationFor("com.example.SomeClass$SomeInnerClass")

【讨论】:

  • 永远不会太晚!
  • @RichardT 很高兴有一个示例代码 sn-p 显示 @SuppressStaticInitializationFor 的用法
【解决方案2】:

@PrepareForTest({GLFW.class}) 为已在 ClassLoader 中加载的本机库 lwjgl.dll 加载 ClassLoader。

您可以使用@PowerMockIgnore 将具有提供给 value() 的名称的类的加载延迟到系统 ClassLoader。

例如,假设您想延迟加载 org.myproject 包及其所有子包中的所有类,但您仍想准备“MyClass”进行测试。然后你这样做:


 @PowerMockIgnore("org.myproject.*")
 @PrepareForTest(MyClass.class)
 @RunWith(PowerMockRunner.class)
 public class MyTest {
 ...
 }

JavaDoc Reference

【讨论】:

    【解决方案3】:

    @PrepareForTest({GLFW.class}) 创建新的ClassLoader 并在其中加载修改后的类。我怀疑GLFW 在其静态初始化部分加载了lwjgl 库。

    你可以尝试卸载库,但不知道会导致什么后果。

    我建议包装 GLFW 并在您的应用程序中使用该包装器。

    【讨论】:

    • 这是一个非常令人困惑的答案。您是说解决方案是 @PrepareForTest({GLFW.class}) 吗?这就是他的原始代码已经拥有的内容。像你说的wrap GLFW and use that wrapper in your application 是什么样的?请澄清:)
    • @PrepareForTest({GLFW.class}) 不是解决方案,而是问题的原因。它导致重新加载类。类的重新加载导致执行静态部分,执行静态部分导致lwjgl.dll 库的第二次加载。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-16
    相关资源
    最近更新 更多