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

例如:

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

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

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


当前回答

看一看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框架中的严重倒退,使许多测试开发人员的生活变得困难。

其他回答

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

我不确定是否有一种干净的方法可以用JUnit做到这一点,据我所知,JUnit假设所有测试都可以以任意顺序执行。常见问题解答:

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

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

话虽如此,如果您真的想朝着这个方向发展,可以考虑使用TestNG,因为它支持以任意顺序本机运行测试方法(以及诸如指定方法依赖于方法组之类的事情)。Cedric Beust解释了如何按照测试中执行测试的顺序来做这件事。

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

不幸的是,现在没有时间给出一个完整的解决方案,但看看类:

org.junit.runners.Suite

它允许您以特定的顺序(从任何测试类)调用测试用例。

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

这将使您的单元测试保持原样,没有特定的顺序(推荐),无论您是否这样运行它们,然后将这些测试作为更大图景的一部分重新使用。

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

看一看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框架中的严重倒退,使许多测试开发人员的生活变得困难。

迁移到TestNG似乎是最好的方法,但是我没有看到jUnit的明确解决方案。以下是我为jUnit找到的最有可读性的解决方案/格式:

@FixMethodOrder( MethodSorters.NAME_ASCENDING ) // force name ordering
public class SampleTest {
    @Test
    void stage1_prepareAndTest(){};

    @Test
    void stage2_checkSomething(){};

    @Test
    void stage2_checkSomethingElse(){};

    @Test
    void stage3_thisDependsOnStage2(){};

    @Test
    void callTimeDoesntMatter(){}
}

这确保stage2方法在stage1方法之后和stage3方法之前被调用。

附注:我觉得这种方法比jUnit 5.5 @Order注释更好,因为它为读者提供了更好的标记。

JUnit 5更新(以及我的观点)

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

默认情况下,单元测试库不会尝试按照源文件中出现的顺序执行测试。

JUnit 5和JUnit 4一样以这种方式工作。为什么?因为如果顺序很重要,这意味着一些测试在它们之间是耦合的,这对于单元测试来说是不可取的。 所以JUnit 5引入的@Nested特性遵循相同的默认方法。

But for integration tests, the order of the test method may matter since a test method may change the state of the application in a way expected by another test method. For example when you write an integration test for a e-shop checkout processing, the first test method to be executed is registering a client, the second is adding items in the basket and the last one is doing the checkout. If the test runner doesn't respect that order, the test scenario is flawed and will fail. So in JUnit 5 (from the 5.4 version) you have all the same the possibility to set the execution order by annotating the test class with @TestMethodOrder(OrderAnnotation.class) and by specifying the order with @Order(numericOrderValue) for the methods which the order matters.

例如:

@TestMethodOrder(OrderAnnotation.class) 
class FooTest {

    @Order(3)
    @Test
    void checkoutOrder() {
        System.out.println("checkoutOrder");
    }

    @Order(2)
    @Test
    void addItemsInBasket() {
        System.out.println("addItemsInBasket");
    }

    @Order(1)
    @Test
    void createUserAndLogin() {
        System.out.println("createUserAndLogin");
    }
}

输出:

创建用户和登录 添加物品在购物篮 结帐订单

顺便说一下,指定@TestMethodOrder(OrderAnnotation.class)看起来不需要(至少在我测试的5.4.0版本中是这样)。

边注 关于这个问题:JUnit 5是编写集成测试的最佳选择吗?我不认为它应该是首先考虑的工具(Cucumber和co可能经常为集成测试带来更具体的价值和特性),但在一些集成测试用例中,JUnit框架就足够了。所以这个功能的存在是个好消息。