質問
custom をClassLoader
使用して、静的コンテキストから適切に利用されるクラスの実装を提供することは可能ですか?
背景
私は、静的クラスを使用して依存関係を結び付けることを推奨するフレームワークを使用しています。
それはこのように動作します..
public class MyClass {
@ThisIsADependency
private MyDependency myDependency;
public void initialize() {
FrameworkProvidedDependencyResolver.resolveDependencies(this);
}
}
ご想像のとおり、これをテストするのは悪夢であり、JUnit からは不可能なアクティブなフレームワーク環境内から呼び出されない限りFrameworkProvidedDependencyResolver
(実際の名前ではありません) をスローします。NullPointerException
私がやりたい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);
}
}
}
@AutomatedMikeに感謝します。
わかりましたので、テストのためにカスタムの依存関係リゾルバーと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
は実際FrameworkProvidedDependencyResolver
のパッケージ、およびすべてを具体的に見ているため、これも機能しません。
クラスに実際の名前を付けてFrameworkProvidedDependencyResolver
、フレームワークが提供するものと同じパッケージに入れることができます..しかし、今ではClassLoader
. JVMは2つによって混同され、クラスパスによって適切な方がロードされます。おそらく私のものです。ここでの問題は、これがすべてのテストに適用されるようになったことです。私が探している解決策ではありません。
最後に、 は ではないため使用できProxy
ませFrameworkProvidedDependencyResolver
んinterface
。
わかりました、私の質問をもう一度言います:静的コンテキストから適切に利用される
custom を使用して、クラスの実装を提供することは可能ですか? ClassLoader
おそらく、一意の名前を持つ独自の一意のパスにクラスを作成し、それをロードするときに編集して、上書きしようとしている予想されるパスと名前で JVM に表示されるようにすることはできますか? もちろん、他のソリューションも大歓迎です。