私はいくつかの Minecraft の mod を書いており、単体テストを書きたいと思っています。残念ながら、Minecraft のフォージは単体テスト用に構築されていません。
しかし、私は言う:いや!単体テストを書きます!
そのため、Minecraft Forge ではそれnet.minecraft.launchwrapper.LaunchClassLoader
を使用する必要があります。ライブラリ内の事実上すべての関数呼び出しは、このローダーが使用されているというアサーションになり、それ以外の場合は例外をスローします。
これを回避するために、次のテスト クラスの setup メソッドのようにリフレクションを使用することができました。
package net.minecraftforge.oredict;
import static org.junit.Assert.assertEquals;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Collections;
import java.util.Comparator;
import net.minecraft.block.Block;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.launchwrapper.Launch;
import net.minecraft.launchwrapper.LaunchClassLoader;
import org.junit.Before;
import org.junit.Test;
import com.google.common.collect.Ordering;
import com.google.common.io.Files;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.relauncher.FMLRelaunchLog;
import cpw.mods.fml.relauncher.Side;
public class RecipeSorterTest {
public static Ordering<IRecipe> ordering = Ordering.from(new Comparator<IRecipe>() {
@Override
public int compare(IRecipe o1, IRecipe o2) {
return RecipeSorter.INSTANCE.compare(o1, o2);
}
});
private LaunchClassLoader lcl;
@Before
public void setUp() throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
InvocationTargetException, NoSuchFieldException {
Object[] data = new Object[] { "", "", "", "", "1.7.10", "", Files.createTempDir(), Collections.EMPTY_LIST };
URL[] urLs = ((URLClassLoader) Launch.class.getClassLoader()).getURLs();
this.lcl = new LaunchClassLoader(urLs);
Class<?> itemz = lcl.loadClass("cpw.mods.fml.relauncher.FMLRelaunchLog");
Field mz = itemz.getDeclaredField("side");
mz.setAccessible(true);
mz.set(itemz, Enum.valueOf((Class<Enum>) mz.getType(), "CLIENT"));
Class<?> item1 = lcl.loadClass("cpw.mods.fml.common.Loader");
Method m1 = item1.getMethod("injectData", Object[].class);
m1.invoke(null, new Object[] { data });
Class<?> item = lcl.loadClass("net.minecraft.item.Item");
Method m = item.getMethod("registerItems");
m.invoke(null);
// Here's what I'd rather do
// JUnit.setMyClassLoader(new LaunchClassLoader(urLs))
// Loader.injectData(data)
// Item.registerItems();
// Block.registerBlocks();
}
@Test
public void myTest() {
}
}
しかし、これは煩わしく、維持するのも難しく、信頼するのも難しいものです。LaunchClassLoader
したがって、JUnit テストで を使用してクラスをロードするだけの簡単な方法を見つけたいと思います。
私はこの答えを見てきました: Using different classloaders for different JUnit tests?
しかし、それは私が抱えている問題を解決していないようです。そしてLaunchClassLoader
、説明の代わりにを使用して試しても、TestClassLoader
試してみると「実行可能なメソッドがありません」というエラーが発生したため、単体テストを実行できませんでした。
JUnit テストでクラスローダーを設定する簡単な方法はありますか? (いいえ、コードベースを変更することはできません。これは単体テストから行う必要があります)