代码之家  ›  专栏  ›  技术社区  ›  Andrew McKinlay

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

  •  12
  • Andrew McKinlay  · 技术社区  · 14 年前

    从eclipse中,我可以轻松地运行应用程序中的所有junit测试。

    我希望能够在不使用eclipse(或ant或maven或任何其他开发工具)的情况下,从application jar在目标系统上运行测试。

    我可以从命令行看到如何运行特定的测试或套件。

    我可以手动创建一个套件,列出我的应用程序中的所有测试,但这似乎很容易出错-我肯定在某个时候我会创建一个测试,而忘记将它添加到套件中。

    EclipseJUnit插件有一个向导来创建一个测试套件,但是由于某些原因它没有“看到”我的测试类。它可能在寻找junit 3测试,而不是junit 4注释测试。

    我可以编写一个工具,通过扫描源文件自动创建套件。

    或者我可以编写代码,以便应用程序扫描自己的jar文件进行测试(通过命名约定或通过查找@test注释)。

    似乎应该有一个更简单的方法。我错过了什么?

    6 回复  |  直到 9 年前
        1
  •  6
  •   Greg Dubicki    9 年前

    根据 a recent thread 在junit邮件列表中, ClasspathSuite 可以收集并运行类路径上的所有JUnit测试。它并不完全是您想要的,因为它是一个类级注释,但是源是可用的,所以您可以扩展它的内部发现机制。

        2
  •  5
  •   Andrew McKinlay    14 年前

    我的最后一个解决方案遇到了一个小问题。如果我在eclipse中运行“所有测试”,它们会运行两次,因为它们运行单独的测试和套件。我本可以解决这个问题,但后来我意识到有一个更简单的解决方案:

    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");
        }
    
    }
    
        3
  •  4
  •   Andrew McKinlay    14 年前

    基于 http://burtbeckwith.com/blog/?p=52 我想到了以下几点。看来效果不错。

    我可以在代码中运行它:

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

    一个弱点是它依赖于命名约定(“test”后缀)来识别测试。另一个弱点是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;
            }
        }
    
    }
    
        4
  •  1
  •   rhinds    14 年前

    到目前为止,我还没有尝试过,但最近我在博客上看到: http://burtbeckwith.com/blog/?p=52

    作者提供了一个类,该类发现并运行所有JUnit,因此如果您将其插入到项目中,它可能提供所需的功能?

    希望这有帮助。

        5
  •  1
  •   dandan78 Tom Cool    13 年前

    获取Java项目并通过该项目

    JUnitLaunchShortcut jUnitLaunchShortcut = new JUnitLaunchShortcut();
    jUnitLaunchShortcut.launch("Pass the Java Project containing JUnits Classes", "run");
    
        6
  •  0
  •   卢声远 Shengyuan Lu    14 年前

    你也可以用 蚂蚁 它有内置的任务。 编写ant脚本并在目标计算机上运行。 蚂蚁可以因此创建报告。