【问题标题】:How can I run all JUnit unit tests except those ending in "IntegrationTest" in my IntelliJ IDEA project using the integrated test runner?如何使用集成测试运行器在我的 IntelliJ IDEA 项目中运行除以“IntegrationTest”结尾的所有 JUnit 单元测试?
【发布时间】:2010-09-15 16:04:24
【问题描述】:

我基本上想使用 JUnit 的 static suite() 方法在我的 IntelliJ IDEA 项目中运行所有 JUnit unit 测试(不包括 JUnit 集成测试)。为什么使用静态套件()方法?因为然后我可以使用 IntelliJ IDEA 的 JUnit 测试运行器在我的应用程序中运行所有单元测试(并通过命名约定轻松排除所有集成测试)。到目前为止的代码如下所示:

package com.acme;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class AllUnitTests extends TestCase {

    public static Test suite() {
        List classes = getUnitTestClasses();
        return createTestSuite(classes);
    }

    private static List getUnitTestClasses() {
        List classes = new ArrayList();
        classes.add(CalculatorTest.class);
        return classes;
    }

    private static TestSuite createTestSuite(List allClasses) {
        TestSuite suite = new TestSuite("All Unit Tests");
        for (Iterator i = allClasses.iterator(); i.hasNext();) {
            suite.addTestSuite((Class<? extends TestCase>) i.next());
        }
        return suite;
    }

}

应该重写getUnitTestClasses()方法以添加所有扩展TestCase的项目类,除非类名以“IntegrationTest”结尾。

我知道我可以在 Maven 中轻松做到这一点,但我需要在 IntelliJ IDEA 中做到这一点,这样我才能使用集成测试运行器 - 我喜欢绿色条 :)

【问题讨论】:

  • 标记为 Java 以便更多人看到它(不知道它是否真的是 Java 特有的,但它确实使用了 Java)。
  • 附带说明:考虑使用 for-each。你的 for 循环看起来像: for(Class testClass : allClasses) { suite.addTestSuite(testClass); }

标签: java unit-testing reflection junit intellij-idea


【解决方案1】:

解决方案:https://github.com/MichaelTamm/junit-toolbox
使用以下功能

@RunWith(WildcardPatternSuite.class)
@SuiteClasses({"**/*.class", "!**/*IntegrationTest.class"})
public class AllTestsExceptionIntegrationSuit {
}

假设您遵循一种命名模式,其中集成测试以 ...IntegrationTest 结尾,并且您将文件放在最顶层的包中(因此 **/*.class 搜索将有机会获取所有测试)

【讨论】:

    【解决方案2】:

    Spring 在 PathMatchingResourcePatternResolver 中实现了出色的类路径搜索功能。如果您使用 classpath*: 前缀,您可以找到所有资源,包括给定层次结构中的类,甚至可以根据需要过滤它们。然后,您可以使用 AbstractTypeHierarchyTraversingFilter、AnnotationTypeFilter 和 AssignableTypeFilter 的子级在类级别注释或它们实现的接口上过滤这些资源。

    http://static.springsource.org/spring/docs/2.0.x/api/org/springframework/core/io/support/PathMatchingResourcePatternResolver.html

    http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/core/type/filter/AbstractTypeHierarchyTraversingFilter.html

    【讨论】:

      【解决方案3】:

      使用 JUnit4 和 Suite-Runner 怎么样?

      例子:

      @RunWith(Suite.class)
      @Suite.SuiteClasses({
      UserUnitTest.class,
      AnotherUnitTest.class
      })
      public class UnitTestSuite {}
      

      我制作了一个小的 Shell 脚本来查找所有单元测试,并制作了另一个来查找我的集成测试。看看我的博客条目: http://blog.timomeinen.de/2010/02/find-all-junit-tests-in-a-project/

      如果你使用 Spring TestContext,你可以使用 @IfProfile 注解来声明不同的测试。

      亲切的问候, 蒂莫·梅宁

      【讨论】:

        【解决方案4】:

        如何将每个主要的 junit 测试组放入它们自己的根包中。我在我的项目中使用了这个包结构:

        test.
          quick.
            com.acme
          slow.
            com.acme
        

        无需任何编码,您就可以将 IntelliJ 设置为运行所有测试,无论是快速测试还是慢速测试。

        【讨论】:

        • 汉克斯。大多数测试需要与他们测试的类在同一个包中,因为它们访问非公共成员。无论这是否是一个好习惯,现在都无法改变。所以我需要把测试和类放在同一个包里。
        • 这个答案仍然有效。 test/quick 和 test/slow 是测试源的根目录,其中任何一个中的测试仍然在 com.acme 包中。
        • 这是一个不错的选择。这比抓取文件系统要容易得多。它似乎也比通过 ant 运行测试快得多,因为 IntelliJ 只重建已更改的文件。
        • 对 CNelson 的回复:我创建了更多的测试源代码,但问题是 IntelliJ 只允许您对包或类指定的测试进行分组和运行。
        【解决方案5】:

        我已经编写了一些代码来完成大部分工作。只有当您的文件在本地磁盘上而不是在 JAR 中时,它才有效。您所需要的只是包中的一个类。为此,您可以创建一个 Locator.java 类,以便能够找到包。

        public class ClassEnumerator {
            public static void main(String[] args) throws ClassNotFoundException {
                List<Class<?>> list = listClassesInSamePackage(Locator.class, true);
        
                System.out.println(list);
            }
        
            private static List<Class<?>> listClassesInSamePackage(Class<?> locator, boolean includeLocator) 
                                                                              throws ClassNotFoundException {
        
                File packageFile = getPackageFile(locator);
        
                String ignore = includeLocator ? null : locator.getSimpleName() + ".class";
        
                return toClassList(locator.getPackage().getName(), listClassNames(packageFile, ignore));
            }
        
            private static File getPackageFile(Class<?> locator) {
                URL url = locator.getClassLoader().getResource(locator.getName().replace(".", "/") + ".class");
                if (url == null) {
                    throw new RuntimeException("Cannot locate " + Locator.class.getName());
                }
        
                try {
                return new File(url.toURI()).getParentFile();
                }
                catch (URISyntaxException e) {
                    throw new RuntimeException(e);
                }
            }
        
            private static String[] listClassNames(File packageFile, final String ignore) {
                return packageFile.list(new FilenameFilter(){
                    @Override
                    public boolean accept(File dir, String name) {
                        if (name.equals(ignore)) {
                            return false;
                        }
                        return name.endsWith(".class");
                    }
                });
            }
        
            private static List<Class<?>> toClassList(String packageName, String[] classNames)
                                                                     throws ClassNotFoundException {
        
                List<Class<?>> result = new ArrayList<Class<?>>(classNames.length);
                for (String className : classNames) {
                    // Strip the .class
                    String simpleName = className.substring(0, className.length() - 6);
        
                    result.add(Class.forName(packageName + "." + simpleName));
                }
                return result;
            }
        }
        

        【讨论】:

        • 经过一些修改,主要是为了使其递归,这对我来说效果很好。谢谢!
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-03
        • 2019-12-24
        • 2011-09-27
        • 1970-01-01
        • 1970-01-01
        • 2013-10-17
        相关资源
        最近更新 更多