问题
是否可以使用 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 中?当然,任何其他解决方案都是受欢迎的。