1

我正在编写一些 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 测试中设置类加载器?(不,我不能更改代码库,这必须从单元测试中完成)

4

0 回答 0