我正在编写一些 Minecraft 模组,并且我想编写单元测试。不幸的是,Minecraft forge 并不是为进行单元测试而构建的。
但对此我说:不!我会写单元测试!
所以 Minecraft Forge 需要net.minecraft.launchwrapper.LaunchClassLoader
使用它。实际上,库中的任何函数调用都会导致断言正在使用此加载器,在任何其他情况下都会引发异常。
为了避免这种情况,我已经能够像在下面的测试类的设置方法中那样使用反射。
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() {
}
}
但这很烦人,很难维护,也很难信任。所以我想找到一种方法让我的 JUnit 测试使用LaunchClassLoader
加载类。
我已经看到了这个答案: 为不同的 JUnit 测试使用不同的类加载器?
但这似乎并没有解决我遇到的问题。甚至当我尝试它时,使用LaunchClassLoader
而不是TestClassLoader
描述的,我也无法运行任何单元测试,因为每当我尝试时我都会遇到“没有可运行的方法”错误。
有没有一种简单的方法可以在 JUnit 测试中设置类加载器?(不,我不能更改代码库,这必须从单元测试中完成)