1

私はいくつかの 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 テストでクラスローダーを設定する簡単な方法はありますか? (いいえ、コードベースを変更することはできません。これは単体テストから行う必要があります)

4

0 に答える 0