【问题标题】:Grouping JUnit tests对 JUnit 测试进行分组
【发布时间】:2010-10-23 11:03:16
【问题描述】:

有没有办法在 JUnit 中对测试进行分组,以便我只能运行一些组?

或者是否可以注释一些测试然后全局禁用它们?

我正在使用 JUnit 4,我无法使用 TestNG。

编辑: @RunWith 和 @SuiteClasses 效果很好。但是有可能像这样只注释测试类中的一些测试吗?还是我必须注释整个测试类?

【问题讨论】:

标签: java unit-testing junit


【解决方案1】:

JUnit 4.8 支持分组:

public interface SlowTests {}
public interface IntegrationTests extends SlowTests {}
public interface PerformanceTests extends SlowTests {}

然后……

public class AccountTest {

    @Test
    @Category(IntegrationTests.class)
    public void thisTestWillTakeSomeTime() {
        ...
    }

    @Test
    @Category(IntegrationTests.class)
    public void thisTestWillTakeEvenLonger() {
        ...
    }

    @Test
    public void thisOneIsRealFast() {
        ...
    }
}

最后,

@RunWith(Categories.class)
@ExcludeCategory(SlowTests.class)
@SuiteClasses( { AccountTest.class, ClientTest.class })
public class UnitTestSuite {}

取自这里:https://community.oracle.com/blogs/johnsmart/2010/04/25/grouping-tests-using-junit-categories-0

此外,Arquillian 本身也支持分组: https://github.com/weld/core/blob/master/tests-arquillian/src/test/java/org/jboss/weld/tests/Categories.java

【解决方案2】:

您想在测试类中对测试进行分组还是对测试类进行分组?我将假设后者。

这取决于您如何运行测试。如果您通过 Maven 运行它们,则可以准确指定要包含的测试。请参阅the Maven surefire documentation

不过,更一般地说,我所做的是我有一个测试套件树。 JUnit 4 中的测试套件如下所示:

 @RunWith(Suite.class)
 @SuiteClasses({SomeUnitTest1.class, SomeUnitTest2.class})
 public class UnitTestsSuite {
 }

所以,也许我有一个 FunctionTestsSuite 和一个 UnitTestsSuite,然后是一个包含其他两个的 AllTestsSuite。如果你在 Eclipse 中运行它们,你会得到一个非常漂亮的分层视图。

这种方法的问题在于,如果您想以不止一种不同的方式对测试进行切片,这会有点乏味。但这仍然是可能的(例如,您可以拥有一组基于模块切片的套件,然后再根据测试类型切片)。

【讨论】:

  • 必须使用语法:@SuiteClasses({SomeUnitTest1.class, SomeUnitTest2.class})
  • @MatthewHegarty 谢谢,但下次如果您发现代码本身有错别字,请不要犹豫,进行编辑。 PLEASE don't post it as comment(因为评论可能会被其他 cmets 的涌入所掩盖)它对社区非常无益,真的。谢谢!
【解决方案3】:

为了处理全局禁用它们,JUnit(4.5+)有两种方法一种是使用新方法assumeThat。如果将其放在测试类的@BeforeClass(或@Before)中,并且如果条件失败,它将忽略测试。在条件中,您可以放置​​一个系统属性或其他可以全局设置或关闭的东西。

另一种选择是创建一个自定义运行程序,该运行程序了解全局属性并委托给适当的运行程序。这种方法要脆弱得多(因为 JUnit4 内部运行器是不稳定的,并且可以从发布版本更改为发布版本),但它具有能够沿类层次结构继承并在子类中被覆盖的优点。如果您必须支持旧版 JUnit38 类,这也是唯一可行的方法。

这是一些执行自定义 Runner 的代码。关于 getAppropriateRunnerForClass 可能会做什么,我实现它的方式是有一个单独的注释来告诉自定义运行器运行什么。唯一的选择是从 JUnit 代码中进行一些非常脆弱的复制粘贴。

private class CustomRunner implements Runner
 private Runner runner;

    public CustomRunner(Class<?> klass, RunnerBuilder builder) throws Throwable {
        if (!isRunCustomTests()) {
            runner = new IgnoredClassRunner(klass);
        } else {
            runner = getAppropriateRunnerForClass(klass, builder);
    }

    public Description getDescription() {
        return runner.getDescription();
    }

    public void run(RunNotifier notifier) {
        runner.run(notifier);
    }
}

编辑:@RunWith 标签仅适用于整个班级。解决该限制的一种方法是将测试方法移动到静态内部类并对其进行注释。这样,您就可以利用类组织的注释。但是,这样做对任何 @Before 或 @BeforeClass 标签都没有帮助,您将不得不在内部类中重新创建它们。它可以调用外部类的方法,但它必须有自己的方法作为钩子。

【讨论】:

    【解决方案4】:

    在 JUnit 5 中,您可以在类或方法级别声明 @Tag 用于过滤测试;类似于 TestNG 中的测试组或 JUnit 4 中的类别

    来自javadoc

    标签用于过滤为给定测试执行的测试 计划。例如,开发团队可能会使用诸如 为“fast”、“slow”、“ci-server”等,然后提供标签列表 用于当前的测试计划,可能取决于 当前环境。

    例如,您可以使用 "slow" @Tag 声明一个测试类,它将被所有方法继承,并在需要时为某些方法覆盖它:

    import org.junit.jupiter.api.Tag;
    import org.junit.jupiter.api.Test;
    
    @Tag("slow") 
    public class FooTest{
    
       // 
       @Test
       void loadManyThings(){ 
            ...
       }
    
       @Test
       void loadManyManyThings(){ 
            ...
       }
    
    
       @Test
       @Tag("fast")
       void loadFewThings(){ 
            ...
       }
    
    }
    

    您可以对其他测试类应用相同的逻辑。
    这样,测试类(和方法)也属于一个特定的标签。

    最好不要在整个测试类中复制和粘贴@Tag("fast")@Tag("slow"),而是创建自定义组合注释。
    例如:

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    import org.junit.jupiter.api.Tag;
    
    @Target({ ElementType.TYPE, ElementType.METHOD })
    @Retention(RetentionPolicy.RUNTIME)
    @Tag("slow")
    public @interface Slow {
    }
    

    并将其用作:

    @Test
    @Slow
    void slowProcessing(){ 
        ...
    }   
    

    要在文本执行期间启用或禁用标有特定标签的测试,您可以依赖maven-surefire-plugin documentation

    要包含标签或标签表达式,请使用groups

    要排除标签或标签表达式,请使用excludedGroups

    只需根据您的要求在您的 pom.xml 中配置插件(文档示例):

     <build>
         <plugins>
             ...
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-surefire-plugin</artifactId>
                 <version>2.22.0</version>
                 <configuration>
                     <groups>acceptance | !feature-a</groups>
                     <excludedGroups>integration, regression</excludedGroups>
                 </configuration>
             </plugin>
         </plugins> 
    </build> 
    

    有关信息,test goal documentation 未更新。

    【讨论】:

      【解决方案5】:

      试试JUnit Test Groups。来自文档:

      @TestGroup("integration")
      public class MyIntegrationTest {
         @ClassRule
         public static TestGroupRule rule = new TestGroupRule();
      
         ...
      }
      
      • 执行一个简单的测试组:-Dtestgroup=integration
      • 执行多个测试组:-Dtestgroup=group1,group2
      • 执行所有测试组:-Dtestgroup=all

      【讨论】:

        【解决方案6】:

        您可以创建包含测试组的测试Suite 对象。或者,您的 IDE(如 Eclipse)可能支持运行给定包中包含的所有测试。

        【讨论】:

          【解决方案7】:

          您可以使用 Test Suite(http://qaautomated.blogspot.in/2016/09/junit-test-suits-and-test-execution.html) 或 Junit Categories(http://qaautomated.blogspot.in/2016/09/junit-categories.html) 来有效地对测试用例进行分组。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-12-17
            相关资源
            最近更新 更多