问题
是否可以使用 custom 提供一个类的实现ClassLoader,以便从静态上下文中正确使用?
背景
我正在使用一个框架,该框架建议我们使用静态类来连接依赖项。
它的工作原理是这样的..
public class MyClass {
@ThisIsADependency
private MyDependency myDependency;
public void initialize() {
FrameworkProvidedDependencyResolver.resolveDependencies(this);
}
}
正如您所料,这是一个测试的噩梦,而且,果然FrameworkProvidedDependencyResolver(不是真名)抛出一个NullPointerException除非从活动框架环境中调用,而这在 JUnit 中是不可能的。
我想做的是提供一个自定义ClassLoader,我可以在 JUnit 测试中使用它来提供一个FrameworkProvidedDependencyResolver连接模拟依赖项或其他任何东西的自定义。
好的,这就是我希望我的单元测试看起来像的样子:
@RunWith(MyTestRunner.class)
public class TestMyClass {
@Test
public void testInitialization() {
MyClass myClass = new MyClass();
myClass.initialize();
// not much of a test, I know
}
}
MyTestRunner是我选择使用我的自定义ClassLoader..
public class MyTestRunner extends BlockJUnit4ClassRunner {
public MyTestRunner(Class<?> clazz) throws InitializationError {
super(getFromMyClassLoader(clazz));
}
private static Class<?> getFromMyClassLoader(Class<?> clazz) throws InitializationError {
try {
ClassLoader testClassLoader = new MyClassLoader();
return Class.forName(clazz.getName(), true, testClassLoader);
} catch (ClassNotFoundException e) {
throw new InitializationError(e);
}
}
}
好的,这样MyClassLoader我就有机会换掉FrameworkProvidedDependencyResolver自定义依赖解析器进行测试了。
public class ZKTestClassLoader extends URLClassLoader {
public ZKTestClassLoader() {
super(((URLClassLoader) getSystemClassLoader()).getURLs());
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
Class<?> loadedClass = findLoadedClass(name);
if (loadedClass != null) {
return loadedClass;
}
System.out.println("Loading " + name);
if (name.startsWith("my.test.classes")) {
// Make sure we use MyClassLoader to load the test classes,
// thus any classes it loads (eg: MyClass) will come through here.
return super.findClass(name);
} else if (name.endsWith("FrameworkProvidedDependencyResolver")) {
// What should do we do here?
}
return super.loadClass(name);
}
}
好的,所以现在我们可以加载自定义FrameworkProvidedDependencyResolver而不是框架提供的自定义了.. 但是我该怎么做呢?
我可以忽略对“FrameworkProvidedDependencyResolver”的请求并返回另一个类,例如“MyMockFrameworkProvidedDependencyResolver”。这很好,但是当从静态上下文MyClass.initialize调用时FrameworkProvidedDependencyResolver,我们得到一个NoClassDefFoundError. 说得通。
我可以尝试将其命名MyMockFrameworkProvidedDependencyResolver为与真实相同的名称FrameworkProvidedDependencyResolver并将其放入另一个包中(例如:)i.hate.my.framework.FrameworkProvidedDependencyResolver。这也不起作用,因为MyClass它专门查看 real FrameworkProvidedDependencyResolver、 package 和所有内容。
我可以尝试将我的类命名为真实类FrameworkProvidedDependencyResolver,并将其放在与我的框架提供的相同的包中。但现在我什至不需要ClassLoader. JVM 会被这两者混淆并加载类路径中合适的那个,可能是我的。这里的问题是这现在适用于所有测试。不是我正在寻找的解决方案。
最后,我不能使用Proxy,因为FrameworkProvidedDependencyResolver不是interface.
好的,重申我的问题:
是否可以使用 custom 提供一个类的实现ClassLoader,它将在静态上下文中正确使用?也许,我是否可以在它自己的唯一路径中拥有一个具有唯一名称的类,我可以在加载它时对其进行编辑,以便它以我试图覆盖的预期路径和名称出现在 JVM 中?当然,任何其他解决方案都是受欢迎的。