首页 文章

如何在JUnit4中按特定顺序运行测试方法?

提问于
浏览
361

我想执行按特定顺序由 @Test 注释的测试方法 .

例如:

public class MyTest {
    @Test public void test1(){}
    @Test public void test2(){}
}

我希望确保在每次运行 MyTest 之前在 test2() 之前运行 test1() ,但我找不到像 @Test(order=xx) 这样的注释 .

我认为's quite important feature for JUnit, if author of JUnit doesn'吨想要 order feature ,为什么?

16 回答

  • 210

    我认为这对JUnit来说非常重要,如果JUnit的作者不想要订单功能,为什么?

    我不确定JUnit是否有一种干净的方法,据我所知,JUnit假设所有测试都可以按任意顺序执行 . 来自FAQ:

    我如何使用测试夹具? (...)不保证测试方法调用的顺序,因此testOneItemCollection()可能在testEmptyCollection()之前执行 . (......)

    为什么会这样?好吧,我认为让测试顺序依赖是一种做法,作者不应该加入并违反这个做法,使事情更难以维护,会破坏单独运行测试的能力(显然)等等 .

    话虽这么说,如果你真的想要朝着这个方向前进,可以考虑使用TestNG,因为它支持以任意顺序本地运行测试方法(而且指定方法取决于方法组) . Cedric Beust在order of execution of tests in testng解释了如何做到这一点 .

  • 2

    如果您删除现有的Junit实例,并在构建路径中下载JUnit 4.11或更高版本,则以下代码将按其名称的顺序执行测试方法,并按升序排序:

    @FixMethodOrder(MethodSorters.NAME_ASCENDING)
    public class SampleTest {
    
        @Test
        public void testAcreate() {
            System.out.println("first");
        }
        @Test
        public void testBupdate() {
            System.out.println("second");
        }
        @Test
        public void testCdelete() {
            System.out.println("third");
        }
    }
    
  • 2

    如果订单很重要,您应该自己下订单 .

    @Test public void test1() { ... }
    @Test public void test2() { test1(); ... }
    

    特别是,如有必要,您应列出一些或所有可能的订单排列进行测试 .

    例如,

    void test1(); 
    void test2(); 
    void test3(); 
    
    
    @Test
    public void testOrder1() { test1(); test3(); }
    
    @Test(expected = Exception.class)
    public void testOrder2() { test2(); test3(); test1(); }
    
    @Test(expected = NullPointerException.class)
    public void testOrder3() { test3(); test1(); test2(); }
    

    或者,对所有排列进行全面测试:

    @Test
    public void testAllOrders() {
        for (Object[] sample: permute(1, 2, 3)) {
            for (Object index: sample) {
                switch (((Integer) index).intValue()) {
                    case 1: test1(); break; 
                    case 2: test2(); break; 
                    case 3: test3(); break; 
                }
            }
        }
    }
    

    这里, permute() 是一个简单的函数,它将所有可能的permations迭代到一个数组集合中 .

  • 6

    迁移到TestNG似乎是最好的方法,但我看不到jUnit的明确解决方案 . 这是我为jUnit找到的最多 readable solution / formatting

    @FixMethodOrder(MethodSorters.NAME_ASCENDING)
    public class SampleTest {
        @Test
        void stage1_prepareAndTest(){};
    
        @Test
        void stage2_checkSomething(){};
    
        @Test
        void stage2_checkSomethingElse(){};
    
        @Test
        void stage3_thisDependsOnStage2(){};
    
        @Test
        void callTimeDoesntMatter(){}
    }
    

    这确保stage1方法在stage1之后和stage3之前调用 .

  • 49

    这是我在Junit工作时遇到的主要问题之一,我提出了以下解决方案,对我来说很好:

    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Comparator;
    import java.util.List;
    
    import org.junit.runners.BlockJUnit4ClassRunner;
    import org.junit.runners.model.FrameworkMethod;
    import org.junit.runners.model.InitializationError;
    
    public class OrderedRunner extends BlockJUnit4ClassRunner {
    
        public OrderedRunner(Class<?> clazz) throws InitializationError {
            super(clazz);
        }
    
        @Override
        protected List<FrameworkMethod> computeTestMethods() {
            List<FrameworkMethod> list = super.computeTestMethods();
            List<FrameworkMethod> copy = new ArrayList<FrameworkMethod>(list);
            Collections.sort(copy, new Comparator<FrameworkMethod>() {
    
                @Override
                public int compare(FrameworkMethod f1, FrameworkMethod f2) {
                    Order o1 = f1.getAnnotation(Order.class);
                    Order o2 = f2.getAnnotation(Order.class);
    
                    if (o1 == null || o2 == null) {
                        return -1;
                    }
    
                    return o1.order() - o2.order();
                }
            });
            return copy;
        }
    }
    

    还创建如下界面:

    @Retention(RetentionPolicy.RUNTIME)
    
    
    @Target({ ElementType.METHOD})
    
    public @interface Order {
    public int order();
    }
    

    现在假设你有A类,你已经写了几个测试用例,如下所示:

    (@runWith=OrderRunner.class)
    Class A{
    @Test
    @Order(order = 1)
    
    void method(){
    
    //do something
    
    }
    
    }
    

    因此,执行将从名为“method()”的方法开始 . 谢谢!

  • 34

    (尚未发布)更改https://github.com/junit-team/junit/pull/386引入了 @SortMethodsWith . https://github.com/junit-team/junit/pull/293至少在没有它的情况下使订单可预测(在Java 7中它可以是非常随机的) .

  • 8

    查看JUnit报告 . JUnit已经按包组织 . 每个包都有(或可以有)TestSuite类,每个类依次运行多个TestCase . 每个TestCase都可以有多个 public void test*() 形式的测试方法,每个测试方法实际上都会成为它们所属的TestCase类的一个实例 . 每个测试方法(TestCase实例)都有一个名称和通过/失败标准 .

    我的管理层需要的是单个 TestStep 项目的概念,每个项目都报告自己的通过/未通过标准 . 任何测试步骤的失败都不得妨碍后续测试步骤的执行 .

    过去,我职位的测试开发人员将TestCase类组织成与被测产品的部件相对应的包,为每个测试创建一个TestCase类,并使每个测试方法成为测试中的单独“步骤”,在JUnit输出中完成自己的通过/失败标准 . 每个TestCase都是一个独立的“测试”,但TestCase中的各个方法或测试“步骤”必须按特定顺序进行 .

    TestCase方法是TestCase的步骤,测试设计者在每个测试步骤中获得单独的通过/失败标准 . 现在测试步骤混乱,测试(当然)失败 .

    例如:

    Class testStateChanges extends TestCase
    
    public void testCreateObjectPlacesTheObjectInStateA()
    public void testTransitionToStateBAndValidateStateB()
    public void testTransitionToStateCAndValidateStateC()
    public void testTryToDeleteObjectinStateCAndValidateObjectStillExists()
    public void testTransitionToStateAAndValidateStateA()
    public void testDeleteObjectInStateAAndObjectDoesNotExist()
    public void cleanupIfAnythingWentWrong()
    

    每种测试方法都断言并报告其自己的单独通过/未通过标准 . 为了订购,将其折叠为“一个大的测试方法”会丢失JUnit摘要报告中每个“步骤”的通过/失败标准粒度 . ......这让我的经理感到不安 . 他们目前要求另一种选择 .

    任何人都可以解释一下,带有加扰测试方法排序的JUnit如何支持每个顺序测试步骤的单独通过/失败标准,如上所述并且我的管理层要求?

    无论文档如何,我都认为这是JUnit框架中的一个严重的回归,它使许多测试开发人员的生活变得困难 .

  • 1

    当测试用例作为套件运行时,您想要的是完全合理的 .

    不幸的是现在没有时间提供完整的解决方案,但看看课程:

    org.junit.runners.Suite
    

    这允许您按特定顺序调用测试用例(来自任何测试类) .

    这些可能用于创建功能,集成或系统测试 .

    这使您的单元测试没有特定顺序(如建议的那样),无论你是否运行它们,然后重新使用测试作为更大图片的一部分 .

    我们为单元,集成和系统测试重用/继承相同的代码,有时是数据驱动的,有时是提交驱动的,有时是作为套件运行的 .

  • 0

    我不确定是否同意,如果我想测试'文件上传'然后测试'文件上传插入的数据',为什么我不希望它们彼此独立?非常合理我认为能够单独运行它们而不是同时使用Goliath测试用例 .

  • 0

    在这里查看我的解决方案:“Junit和java 7.”

    在本文中,我将介绍如何按顺序运行junit测试 - “就像在源代码中一样” . 将按照测试方法出现在类文件中的顺序运行测试 .

    http://intellijava.blogspot.com/2012/05/junit-and-java-7.html

    但正如Pascal Thivent所说,这不是一个好习惯 .

  • 0

    JUnit目前允许测试方法使用类注释运行排序:

    @FixMethodOrder(MethodSorters.NAME_ASCENDING)
    @FixMethodOrder(MethodSorters.JVM)
    @FixMethodOrder(MethodSorters.DEFAULT)
    

    要设置方法顺序,您可以将它们命名为:

    a_TestWorkUnit_WithCertainState_ShouldDoSomething b_TestWorkUnit_WithCertainState_ShouldDoSomething c_TestWorkUnit_WithCertainState_ShouldDoSomething

    你可以找到examples here .

  • 3

    我已经阅读了几个答案并同意它不是最佳实践,但是最简单的订购测试方法 - 以及JUnit默认运行测试的方式是按字母名称升序 .

    因此,只需按照您想要的字母顺序命名测试 . 另请注意,测试名称必须以单词test开头 . 请注意数字

    test12将在test2之前运行

    所以:

    testA_MyFirstTest testC_ThirdTest testB_ATestThatRunsSecond

  • 64

    请看看这个:https://github.com/TransparentMarket/junit . 它按照指定的顺序运行测试(在已编译的类文件中定义) . 它还具有一个AllTests套件,可以首先运行子包定义的测试 . 使用AllTests实现,可以扩展解决方案,同时过滤属性(我们曾经使用@Fast注释,但那些尚未发布) .

  • 3

    这是JUnit的扩展,可以产生所需的行为:https://github.com/aafuks/aaf-junit

    我知道这是针对JUnit哲学的作者,但是当在非严格单元测试的环境中使用JUnit时(在Java中实践),这可能非常有用 .

  • 14

    我最后在这里认为我的测试没有按顺序运行,但事实是,混乱是在我的异步工作中 . 使用并发时,您还需要在测试之间执行并发检查 . 在我的例子中,作业和测试共享一个信号量,因此下一个测试会挂起,直到正在运行的作业释放锁定 .

    我知道这与这个问题并不完全相关,但可能有助于针对正确的问题

  • 0

    你可以使用以下代码之一:

    @FixMethodOrder(MethodSorters.JVM)OR `@FixMethodOrder(MethodSorters.DEFAULT)` OR `@FixMethodOrder(MethodSorters.NAME_ASCENDING)` before your test class like this:
    
    
    @FixMethodOrder(MethodSorters.NAME_ASCENDING)
    
    
    public class BookTest { ...}
    

相关问题