Java JUnitCore未加载测试用例中所需的LIB

Java JUnitCore未加载测试用例中所需的LIB,java,junit,classloader,junit4,dynamic-class-loaders,Java,Junit,Classloader,Junit4,Dynamic Class Loaders,我试图编写一个动态运行外部类测试的方法。我能够运行仅使用JDK库的测试,但是当我运行使用另一个库(如org.jmock.mockry)的测试时,JUnitCore.run(args)返回的结果对象有以下错误: [initializationError(package.TestClass): org/jmock/Mockery] java.lang.NoClassDefFoundError: org/jmock/Mockery com.sun.jdi.ClassNotLoadedExceptio

我试图编写一个动态运行外部类测试的方法。我能够运行仅使用JDK库的测试,但是当我运行使用另一个库(如org.jmock.mockry)的测试时,JUnitCore.run(args)返回的结果对象有以下错误:

[initializationError(package.TestClass): org/jmock/Mockery]
java.lang.NoClassDefFoundError: org/jmock/Mockery

com.sun.jdi.ClassNotLoadedException: Type has not been loaded occurred while retrieving component type of array.
不用说,如果我从eclipse中的原始项目运行测试,测试就会运行并通过

我相信这个问题与类路径有关,因为类加载器似乎只是加载被测试的类,而不是加载外部项目类路径中定义的依赖项(如JAR)。我不知道如何将JAR动态加载到正在执行的应用程序中

下面是加载类并运行测试的代码

URL url = new File("E:\eclipseProjectName\bin\").toURL();
final URL[] urls = new URL[] { url };
final ClassLoader cl = new URLClassLoader(urls);
@SuppressWarnings("rawtypes")
final Class cls = cl.loadClass("package.ClassName");
final JUnitCore core = new JUnitCore();
final Result result = new JUnitCore().run(Request.method(cls, "methodName"));
提前感谢,


马克·卡奇亚我不知道你说的是什么意思:

我相信这个问题和类加载器一样与类路径有关 似乎只加载被测试的类,不加载 外部项目的类路径中定义的依赖项(如JAR)

如果您想访问java中的类,您必须将其放在类路径上,或者自己查找并加载它。看起来您正在使用自己的类加载器将Eclipse项目bin路径添加到类路径中,但是没有将mockry添加到类路径中。EclipseBin路径仅包含已编译的类。您需要专门加载mockryjar,或者更好,使用
java-cp
将所有内容放到jvm的类路径上

好了,我开始理解这个问题了。您试图在其他人的项目中运行一组测试,但如果测试引用其他依赖项,则无法运行。简单的回答是:这很难。您正试图根据外部项目的引用类/JAR确定需要将哪些类添加到类加载器中

有几种方法可以做到这一点。如果您确定外部项目是使用Eclipse构建的,那么您可以查看
.project
.classpath
来查找外部项目的依赖项。这并不简单,因为它们可以包含对其他容器的引用。这是我的一个项目中的.classpath:

<?xml version="1.0" encoding="UTF-8"?>
<classpath>
  <classpathentry kind="src" output="target/classes" path="src/main/java"/>
  <classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"/>
  <classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
  <classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"/>
  <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
  <classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
  <classpathentry kind="output" path="target/classes"/>
</classpath>

另外,如果您在jenkins下运行并构建项目,您也会得到很好的报告。

如果您想加载正在运行测试的应用程序中使用的库,那么您需要设置
URLClassLoader
来加载当前的类加载器,然后再加载对所需类的引用我们正在尝试测试

 URLClassLoader cl = new URLClassLoader(classLoaderUrls, getClass().getClassLoader());
下面是一个从jar动态加载类的示例。如果您只想按名称加载一个类,您可以如上所述

    File pathToJar = new File(jarPath);

    JarFile jarFile;
    jarFile = new JarFile(pathToJar);
    Enumeration<JarEntry> e = jarFile.entries();

    URL[] classLoaderUrls = new URL[]{pathToJar.toURI().toURL()};

    URLClassLoader cl = new URLClassLoader(classLoaderUrls, getClass().getClassLoader());
    while (e.hasMoreElements()) {

        // load all the classes in the jar (or you can set it up to use the exact class/method name as you did above
        JarEntry je = e.nextElement();
        if(je.isDirectory() || !je.getName().endsWith(".class")){
            continue;
        }
        // -6 because of .class
        String className = je.getName().substring(0,je.getName().length()-6);
        className = className.replace('/', '.');
        Class c = cl.loadClass(className);


        JUnitCore junit = new JUnitCore();
        Result result = junit.runClasses(c);
        // check for failed/ passed tests here

     }
filepathtojar=新文件(jarPath);
JarFile-JarFile;
jarFile=新的jarFile(pathToJar);
枚举e=jarFile.entries();
URL[]classLoaderUrls=新URL[]{pathToJar.toURI().toURL()};
URLClassLoader cl=新的URLClassLoader(classLoaderUrls,getClass().getClassLoader());
而(e.hasMoreElements()){
//加载jar中的所有类(或者您可以像上面所做的那样将其设置为使用确切的类/方法名)
JarEntry je=e.nextElement();
if(je.isDirectory()| |!je.getName().endsWith(“.class”)){
继续;
}
//-6因为上课
字符串className=je.getName().substring(0,je.getName().length()-6);
className=className.replace(“/”,“.”);
c类=cl.loadClass(类名);
JUnitCore junit=新的JUnitCore();
结果=junit.runClasses(c);
//在此处检查失败/通过的测试
}

您是如何运行测试的?Eclipse、Ant等等?您是如何在测试运行程序中设置类路径的?测试是用上面的代码以编程方式运行的。不过,我不知道如何在执行开始后动态地将JAR添加到类路径中,我认为这就是问题所在。我已经做了很多研究,似乎这是不可能的我可以这样做,但IDE确实运行外部测试,例如一个正在编码的程序中的测试。您如何知道要加载哪些外部JAR?用户必须指定它们所在的路径。我的问题是,我不知道如何加载它们或以某种方式在测试运行程序中引用它们谢谢您的回答。可能我不清楚。在这个应用程序中例如,我将动态加载外部测试并运行它们,因此在用户指向他的java项目之前,我不知道将使用哪些库。请问我如何在运行时以编程方式加载外部库?@cachiama:实际应用程序运行时可能是这样,但现在我们讨论的是测试您编写的sts应该是确定性的,并且总是产生相同的结果。因此,您应该知道您的测试代码试图加载的依赖项。同样,我认为我没有明确说明。我的应用程序的目的是动态加载外部应用程序的测试并运行它们,并显示哪些测试通过了,哪些没有通过。问题是在运行外部测试并使用某些外部库时,我的应用程序中的JUnitCore会在内部捕获ClassNotFound异常,测试显然会失败。我想加载外部应用程序当前使用的库,以便我的应用程序上的JUnitCore能够加载引用的类。感谢您的回复这很有帮助。到目前为止,这是一个概念证明,因此我可以安全地假设该项目是一个eclipse项目,库将以jar格式存储在任何文件夹中。您认为有可能在运行时加载这些引用库,而不是在运行前添加到我的应用程序的类路径中吗?
    File pathToJar = new File(jarPath);

    JarFile jarFile;
    jarFile = new JarFile(pathToJar);
    Enumeration<JarEntry> e = jarFile.entries();

    URL[] classLoaderUrls = new URL[]{pathToJar.toURI().toURL()};

    URLClassLoader cl = new URLClassLoader(classLoaderUrls, getClass().getClassLoader());
    while (e.hasMoreElements()) {

        // load all the classes in the jar (or you can set it up to use the exact class/method name as you did above
        JarEntry je = e.nextElement();
        if(je.isDirectory() || !je.getName().endsWith(".class")){
            continue;
        }
        // -6 because of .class
        String className = je.getName().substring(0,je.getName().length()-6);
        className = className.replace('/', '.');
        Class c = cl.loadClass(className);


        JUnitCore junit = new JUnitCore();
        Result result = junit.runClasses(c);
        // check for failed/ passed tests here

     }