简体   繁体   English

如何在Java应用程序中以编程方式运行所有JUnit测试?

[英]How do I programmatically run all the JUnit tests in my Java application?

From Eclipse I can easily run all the JUnit tests in my application. 从Eclipse我可以轻松地在我的应用程序中运行所有JUnit测试。

I would like to be able to run the tests on target systems from the application jar, without Eclipse (or Ant or Maven or any other development tool). 我希望能够在没有Eclipse(或Ant或Maven或任何其他开发工具)的情况下从应用程序jar运行目标系统上的测试。

I can see how to run a specific test or suite from the command line. 我可以看到如何从命令行运行特定的测试或套件。

I could manually create a suite listing all the tests in my application, but that seems error prone - I'm sure at some point I'll create a test and forget to add it to the suite. 我可以手动创建一个列出我的应用程序中的所有测试的套件,但这似乎容易出错 - 我确信在某些时候我会创建一个测试而忘记将它添加到套件中。

The Eclipse JUnit plugin has a wizard to create a test suite, but for some reason it doesn't "see" my test classes. Eclipse JUnit插件有一个创建测试套件的向导,但由于某种原因,它没有“看到”我的测试类。 It may be looking for JUnit 3 tests, not JUnit 4 annotated tests. 它可能正在寻找JUnit 3测试,而不是JUnit 4注释测试。

I could write a tool that would automatically create the suite by scanning the source files. 我可以编写一个工具,通过扫描源文件自动创建套件。

Or I could write code so the application would scan it's own jar file for tests (either by naming convention or by looking for the @Test annotation). 或者我可以编写代码,以便应用程序扫描它自己的jar文件进行测试(通过命名约定或查找@Test注释)。

It seems like there should be an easier way. 似乎应该有一个更简单的方法。 What am I missing? 我错过了什么?

According to a recent thread on the JUnit mailing list, ClasspathSuite can collect and run all JUnit tests on the classpath. 根据JUnit邮件列表中最近的一个帖子ClasspathSuite可以在类路径上收集和运行所有JUnit测试。 It is not precisely what you want, since it is a class-level annotation, but the source is available, so you may be able to extend its internal discovery mechanism. 它并不是您想要的,因为它是一个类级别的注释,但源是可用的,因此您可以扩展其内部发现机制。

I ran into a minor problem with my last solution. 我的上一个解决方案遇到了一个小问题。 If I ran "all tests" from Eclipse they ran twice because they ran the individual tests AND the suite. 如果我从Eclipse运行“所有测试”,他们会跑两次,因为他们运行了单独的测试和套件。 I could have worked around that, but then I realized there was a simpler solution: 我本可以解决这个问题,但后来我意识到有一个更简单的解决方案:

package suneido;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class RunAllTests {

    public static void run(String jarfile) {
        String[] tests = findTests(jarfile);
        org.junit.runner.JUnitCore.main(tests);
    }

    private static String[] findTests(String jarfile) {
        ArrayList<String> tests = new ArrayList<String>();
        try {
            JarFile jf = new JarFile(jarfile);
            for (Enumeration<JarEntry> e = jf.entries(); e.hasMoreElements();) {
                String name = e.nextElement().getName();
                if (name.startsWith("suneido/") && name.endsWith("Test.class")
                        && !name.contains("$"))
                    tests.add(name.replaceAll("/", ".")
                            .substring(0, name.length() - 6));
            }
            jf.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return tests.toArray(new String[0]);
    }

    public static void main(String[] args) {
        run("jsuneido.jar");
    }

}

Based on http://burtbeckwith.com/blog/?p=52 I came up with the following. 基于http://burtbeckwith.com/blog/?p=52,我想出了以下内容。 It seems to work well. 它似乎运作良好。

I can run it from within my code with: 我可以在我的代码中运行它:

org.junit.runner.JUnitCore.main("suneido.AllTestsSuite");

One weak point is that it relies on a naming convention ("Test" suffix) to identify tests. 一个弱点是它依赖于命名约定(“Test”后缀)来识别测试。 Another weak point is that the name of the jar file is hard coded. 另一个弱点是jar文件的名称是硬编码的。

package suneido;

import java.io.IOException;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.model.InitializationError;

/**
 * Discovers all JUnit tests in a jar file and runs them in a suite.
 */
@RunWith(AllTestsSuite.AllTestsRunner.class)
public final class AllTestsSuite {
    private final static String JARFILE = "jsuneido.jar";

    private AllTestsSuite() {
    }

    public static class AllTestsRunner extends Suite {

        public AllTestsRunner(final Class<?> clazz) throws InitializationError {
            super(clazz, findClasses());
        }

        private static Class<?>[] findClasses() {
            List<String> classFiles = new ArrayList<String>();
            findClasses(classFiles);
            List<Class<?>> classes = convertToClasses(classFiles);
            return classes.toArray(new Class[classes.size()]);
        }

        private static void findClasses(final List<String> classFiles) {
            JarFile jf;
            try {
                jf = new JarFile(JARFILE);
                for (Enumeration<JarEntry> e = jf.entries(); e.hasMoreElements();) {
                    String name = e.nextElement().getName();
                    if (name.startsWith("suneido/") && name.endsWith("Test.class")
                            && !name.contains("$"))
                        classFiles.add(name.replaceAll("/", ".")
                                .substring(0, name.length() - 6));
                }
                jf.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

        private static List<Class<?>> convertToClasses(
                final List<String> classFiles) {
            List<Class<?>> classes = new ArrayList<Class<?>>();
            for (String name : classFiles) {
                Class<?> c;
                try {
                    c = Class.forName(name);
                }
                catch (ClassNotFoundException e) {
                    throw new AssertionError(e);
                }
                if (!Modifier.isAbstract(c.getModifiers())) {
                    classes.add(c);
                }
            }
            return classes;
        }
    }

}

I have not tried this as of yet, but came across this blog recently: http://burtbeckwith.com/blog/?p=52 我还没有尝试过这个,但最近遇到了这个博客: http//burtbeckwith.com/blog/?p = 52

The author provides a class that discovers all your junits and runs them, so if you slot this in to your project it may provide the capability required? 作者提供了一个发现所有junits并运行它们的类,所以如果你将它插入到你的项目中它可能提供所需的功能?

Hope this helps. 希望这可以帮助。

Get the Java project and pass the project 获取Java项目并传递项目

JUnitLaunchShortcut jUnitLaunchShortcut = new JUnitLaunchShortcut();
jUnitLaunchShortcut.launch("Pass the Java Project containing JUnits Classes", "run");

You also could use ANT which has built-in task. 您也可以使用具有内置任务的ANT Write ANT script and run it on target machine. 编写ANT脚本并在目标计算机上运行它。 ANT could create report as result. ANT可以创建报告作为结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM