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

问题描述 投票:379回答:17

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

例如:

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

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

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

java unit-testing junit junit4
17个回答
225
投票

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

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

How do I use a test fixture?

(...)不保证测试方法调用的顺序,因此testOneItemCollection()可能在testEmptyCollection()之前执行。 (......)

为什么会这样?好吧,我相信让测试顺序依赖是作者不想推广的做法。测试应该是独立的,它们不应该是耦合的,违反它会使事情变得更难维护,会破坏单独运行测试的能力(显然)等等。

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


3
投票

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


2
投票

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

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

org.junit.runners.Suite

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


0
投票

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

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

test12将在test2之前运行

所以:

testA_MyFirstTest testC_ThirdTest testB_ATestThatRunsSecond


0
投票

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


0
投票

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

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


0
投票

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

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


0
投票

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

https://github.com/aafuks/aaf-junit

0
投票

使用JUnit 5.4,您可以指定顺序:

@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 { ...}

你只需要注释你的课程

@Test
@Order(2)
public void sendEmailTestGmail() throws MessagingException {

@TestMethodOrder(OrderAnnotation.class)

我在我的项目中使用它,它工作得很好!


76
投票

如果您删除现有的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");
    }
}

48
投票

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

@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; 
            }
        }
    }
}

在这里,qazxsw poi是一个简单的函数,它将所有可能的排列迭代到一个数组集合中。


44
投票

迁移到TestNG似乎是最好的方法,但我看不到jUnit的明确解决方案。这是我为jUnit找到的最易读的解决方案/格式:

permute()

这确保了在阶段1之后和阶段3之前调用阶段2方法。


18
投票

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

@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(){}
}

还创建如下界面:

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;
    }
}

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

 @Retention(RetentionPolicy.RUNTIME)


@Target({ ElementType.METHOD})

public @interface Order {
public int order();
}

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


8
投票

(尚未发布)改变(@runWith=OrderRunner.class) Class A{ @Test @Order(order = 1) void method(){ //do something } } 引入了https://github.com/junit-team/junit/pull/386@SortMethodsWith至少在没有它的情况下使订单可预测(在Java 7中它可以是非常随机的)。


6
投票

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

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

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

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

例如:

public void test*()

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

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

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


6
投票

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

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()

默认情况下,测试方法按字母顺序运行。因此,要设置特定的方法顺序,您可以将它们命名为:

a_TestWorkUnit_WithCertainState_ShouldDoSomething b_TestWorkUnit_WithCertainState_ShouldDoSomething c_TestWorkUnit_WithCertainState_ShouldDoSomething

你可以找到@FixMethodOrder(MethodSorters.NAME_ASCENDING) @FixMethodOrder(MethodSorters.JVM) @FixMethodOrder(MethodSorters.DEFAULT)


3
投票

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

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

examples here

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

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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.