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

发布于 2024-09-18 17:42:47 字数 372 浏览 5 评论 0 原文

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

例如:

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

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

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

I want to execute test methods which are annotated by @Test in specific order.

For example:

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

I want to ensure to run test1() before test2() each time I run MyTest, but I couldn't find annotation like @Test(order=xx).

I think it's quite important feature for JUnit, if author of JUnit doesn't want the order feature, why?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(22

心在旅行 2024-09-25 17:42:47

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

我不确定是否有一种干净的方法可以使用 JUnit 来执行此操作,据我所知,JUnit 假设所有测试都可以按任意顺序执行。来自常见问题解答:

如何使用测试夹具?

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

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

话虽这么说,如果你真的想要要朝这个方向发展,请考虑使用 TestNG,因为它本身支持以任意顺序运行测试方法(以及指定方法取决于方法组之类的事情)。 Cedric Beust 解释了如何按照 testng 中测试的执行顺序执行此操作。

I think it's quite important feature for JUnit, if author of JUnit doesn't want the order feature, why?

I'm not sure there is a clean way to do this with JUnit, to my knowledge JUnit assumes that all tests can be performed in an arbitrary order. From the FAQ:

How do I use a test fixture?

(...) The ordering of test-method invocations is not guaranteed, so testOneItemCollection() might be executed before testEmptyCollection(). (...)

Why is it so? Well, I believe that making tests order dependent is a practice that the authors don't want to promote. Tests should be independent, they shouldn't be coupled and violating this will make things harder to maintain, will break the ability to run tests individually (obviously), etc.

That being said, if you really want to go in this direction, consider using TestNG since it supports running tests methods in any arbitrary order natively (and things like specifying that methods depends on groups of methods). Cedric Beust explains how to do this in order of execution of tests in testng.

却一份温柔 2024-09-25 17:42:47

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

import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;

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

If you get rid of your existing instance of Junit, and download JUnit 4.11 or greater in the build path, the following code will execute the test methods in the order of their names, sorted in ascending order:

import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;

@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");
    }
}
黑凤梨 2024-09-25 17:42:47

迁移到 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 方法之前调用。

PS 我觉得这种方法比 jUnit 5.5 @Order 注释更好,因为它为读者提供了更好的表示法。

Migration to TestNG seems the best way, but I see no clear solution here for jUnit. Here is most readable solution / formatting I found for 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(){}
}

This ensures stage2 methods are called after stage1 ones and before stage3 ones.

P.S. I feel this approach is better that jUnit 5.5 @Order annotation because it provides better notation for reader.

摘星┃星的人 2024-09-25 17:42:47

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

@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() 是一个简单的函数,它将所有可能的排列迭代到数组集合中。

If the order is important, you should make the order yourself.

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

In particular, you should list some or all possible order permutations to test, if necessary.

For example,

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

Or, a full test of all permutations:

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

Here, permute() is a simple function which iterates all possible permuations into a Collection of array.

放肆 2024-09-25 17:42:47

从 5.5 开始,JUnit 允许在类上使用 @TestMethodOrder(OrderAnnotation.class),在测试方法上允许使用 @Order(1)

JUnit 旧版本允许测试方法使用类注释运行顺序:

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

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

a_TestWorkUnit_WithCertainState_ShouldDoSomething
b_TestWorkUnit_WithCertainState_ShouldDoSomething
c_TestWorkUnit_WithCertainState_ShouldDoSomething

_1_TestWorkUnit_WithCertainState_ShouldDoSomething
_2_TestWorkUnit_WithCertainState_ShouldDoSomething
_3_TestWorkUnit_WithCertainState_ShouldDoSomething

您可以此处找到示例

JUnit since 5.5 allows @TestMethodOrder(OrderAnnotation.class) on class and @Order(1) on test-methods.

JUnit old versions allow test methods run ordering using class annotations:

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

By default test methods are run in alphabetical order. So, to set specific methods order you can name them like:

a_TestWorkUnit_WithCertainState_ShouldDoSomething
b_TestWorkUnit_WithCertainState_ShouldDoSomething
c_TestWorkUnit_WithCertainState_ShouldDoSomething

Or

_1_TestWorkUnit_WithCertainState_ShouldDoSomething
_2_TestWorkUnit_WithCertainState_ShouldDoSomething
_3_TestWorkUnit_WithCertainState_ShouldDoSomething

You can find examples here.

微暖i 2024-09-25 17:42:47

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

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

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

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

但对于集成测试,测试方法的顺序可能很重要,因为一个测试方法可能会以另一个测试方法预期的方式更改应用程序的状态。
例如,当您为电子商店结帐处理编写集成测试时,要执行的第一个测试方法是注册客户端,第二个是在购物篮中添加商品,最后一个是执行结帐。如果测试运行者不遵守该顺序,则测试场景存在缺陷并且将会失败。
因此,在 JUnit 5(从 5.4 版本开始)中,您同样可以通过使用 @TestMethodOrder(OrderAnnotation.class) 并使用 @Order(numericOrderValue) 指定顺序) 对于顺序重要的方法。

例如:

@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 框架就足够了。因此,该功能的存在是一个好消息。

JUnit 5 update (and my opinion)

I think it's quite important feature for JUnit, if author of JUnit doesn't want the order feature, why?

By default, unit testing libraries don't try to execute tests in the order that occurs in the source file.

JUnit 5 as JUnit 4 work in that way. Why? Because if the order matters it means that some tests are coupled between them and that is undesirable for unit tests.
So the @Nested feature introduced by JUnit 5 follows the same default approach.

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.

For example :

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

Output :

createUserAndLogin

addItemsInBasket

checkoutOrder

By the way, specifying @TestMethodOrder(OrderAnnotation.class) looks like not needed (at least in the 5.4.0 version I tested).

Side note
About the question: is JUnit 5 the best choice to write integration tests? I don't think that it should be the first tool to consider (Cucumber and co may often bring more specific value and features for integration tests) but in some integration test cases, the JUnit framework is enough. So that is a good news that the feature exists.

空气里的味道 2024-09-25 17:42:47

这是我在 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()”的方法开始执行。
谢谢!

Its one of the main issue which I faced when I worked on Junit and I came up with following solution which works fine for me:

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

also create a interface like below:

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

Now suppose you have class A where you have written several test cases like below:

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

So execution will start from method named "method()".
Thanks!

与风相奔跑 2024-09-25 17:42:47

(尚未发布)更改 https://github.com/junit-team/junit/ pull/386 引入了@SortMethodsWithhttps://github.com/junit-team/junit/pull/293至少可以让顺序在没有它的情况下是可预测的(在 Java 7 中它可能是相当随机的)。

The (as yet unreleased) change https://github.com/junit-team/junit/pull/386 introduces a @SortMethodsWith. https://github.com/junit-team/junit/pull/293 at least made the order predictable without that (in Java 7 it can be quite random).

自由如风 2024-09-25 17:42:47

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

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

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

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 框架的严重回归,让许多测试开发人员的生活变得困难。

Look at a JUnit report. JUnit is already organized by package. Each package has (or can have) TestSuite classes, each of which in turn run multiple TestCases. Each TestCase can have multiple test methods of the form public void test*(), each of which will actually become an instance of the TestCase class to which they belong. Each test method (TestCase instance) has a name and a pass/fail criteria.

What my management requires is the concept of individual TestStep items, each of which reports their own pass/fail criteria. Failure of any test step must not prevent the execution of subsequent test steps.

In the past, test developers in my position organized TestCase classes into packages that correspond to the part(s) of the product under test, created a TestCase class for each test, and made each test method a separate "step" in the test, complete with its own pass/fail criteria in the JUnit output. Each TestCase is a standalone "test", but the individual methods, or test "steps" within the TestCase, must occur in a specific order.

The TestCase methods were the steps of the TestCase, and test designers got a separate pass/fail criterion per test step. Now the test steps are jumbled, and the tests (of course) fail.

For example:

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

Each test method asserts and reports its own separate pass/fail criteria.
Collapsing this into "one big test method" for the sake of ordering loses the pass/fail criteria granularity of each "step" in the JUnit summary report. ...and that upsets my managers. They are currently demanding another alternative.

Can anyone explain how a JUnit with scrambled test method ordering would support separate pass/fail criteria of each sequential test step, as exemplified above and required by my management?

Regardless of the documentation, I see this as a serious regression in the JUnit framework that is making life difficult for lots of test developers.

财迷小姐 2024-09-25 17:42:47

JUnit 4 更新

从 JUnit 4.13 @OrderWith 开始,可以重现 JUnit 5 @Order 注释。该解决方案与 JUnit 4 的集成比 @RunWith 自定义 BlockJUnit4ClassRunner 实现更好。

以下是我如何用注释排序替换方法名称排序 (@FixMethodOrder(MethodSorters.NAME_ASCENDING))。

@OrderWith(OrderAnnotation.class)
public class MyTest {
    @Test
    @Order(-1)
    public void runBeforeNotAnnotatedTests() {}

    @Test
    public void notAnnotatedTestHasPriority0() {}

    @Test
    @Order(1)
    public void thisTestHasPriority1() {}

    @Test
    @Order(2)
    public void thisTestHasPriority2() {}
}
/**
 * JUnit 4 equivalent of JUnit 5's {@code org.junit.jupiter.api.Order}
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
public @interface Order {
    /**
     * Default order value for elements not explicitly annotated with {@code @Order}.
     *
     * @see Order#value
     */
    int DEFAULT = 0;

    /**
     * The order value for the annotated element.
     * <p>Elements are ordered based on priority where a lower value has greater
     * priority than a higher value. For example, {@link Integer#MAX_VALUE} has
     * the lowest priority.
     *
     * @see #DEFAULT
     */
    int value();
}
import org.junit.runner.Description;
import org.junit.runner.manipulation.Ordering;
import org.junit.runner.manipulation.Sorter;

/**
 * Order test methods by their {@link Order} annotation. The lower value has the highest priority.
 * The tests that are not annotated get the default value {@link Order#DEFAULT}.
 */
public class OrderAnnotation extends Sorter implements Ordering.Factory {
    public OrderAnnotation() {
        super(COMPARATOR);
    }

    @Override
    public Ordering create(Context context) {
        return this;
    }

    private static final Comparator<Description> COMPARATOR = Comparator.comparingInt(
            description -> Optional.ofNullable(description.getAnnotation(Order.class))
                                   .map(Order::value)
                                   .orElse(Order.DEFAULT));
}

未注释的测试的默认优先级为 0。具有相同优先级的测试的顺序未确定。

要点: https://gist.github.com/jcarsique/df98e0bad9e88e8258c4ab34dad3c863

灵感来源:

JUnit 4 update

As of JUnit 4.13 @OrderWith, it is possible to reproduce the JUnit 5 @Order annotation. This solution better integrates with JUnit 4 than @RunWith a custom BlockJUnit4ClassRunner implementation.

Here's how I could replace method name ordering (@FixMethodOrder(MethodSorters.NAME_ASCENDING)) with an ordering by annotation.

@OrderWith(OrderAnnotation.class)
public class MyTest {
    @Test
    @Order(-1)
    public void runBeforeNotAnnotatedTests() {}

    @Test
    public void notAnnotatedTestHasPriority0() {}

    @Test
    @Order(1)
    public void thisTestHasPriority1() {}

    @Test
    @Order(2)
    public void thisTestHasPriority2() {}
}
/**
 * JUnit 4 equivalent of JUnit 5's {@code org.junit.jupiter.api.Order}
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
public @interface Order {
    /**
     * Default order value for elements not explicitly annotated with {@code @Order}.
     *
     * @see Order#value
     */
    int DEFAULT = 0;

    /**
     * The order value for the annotated element.
     * <p>Elements are ordered based on priority where a lower value has greater
     * priority than a higher value. For example, {@link Integer#MAX_VALUE} has
     * the lowest priority.
     *
     * @see #DEFAULT
     */
    int value();
}
import org.junit.runner.Description;
import org.junit.runner.manipulation.Ordering;
import org.junit.runner.manipulation.Sorter;

/**
 * Order test methods by their {@link Order} annotation. The lower value has the highest priority.
 * The tests that are not annotated get the default value {@link Order#DEFAULT}.
 */
public class OrderAnnotation extends Sorter implements Ordering.Factory {
    public OrderAnnotation() {
        super(COMPARATOR);
    }

    @Override
    public Ordering create(Context context) {
        return this;
    }

    private static final Comparator<Description> COMPARATOR = Comparator.comparingInt(
            description -> Optional.ofNullable(description.getAnnotation(Order.class))
                                   .map(Order::value)
                                   .orElse(Order.DEFAULT));
}

The not annotated tests get a default priority of 0. The order of tests with the same priority is undetermined.

Gist: https://gist.github.com/jcarsique/df98e0bad9e88e8258c4ab34dad3c863

Inspired by:

塔塔猫 2024-09-25 17:42:47

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

Not sure I agree, If I want to test 'File Upload' and then test 'Data Inserted by File Upload' why would I not want these to be independent from each other? Perfectly reasonable I think to be able to run them separately rather than having both in a Goliath test case.

迎风吟唱 2024-09-25 17:42:47

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

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

org.junit.runners.Suite

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

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

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

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

What you want is perfectly reasonable when test cases are being run as a suite.

Unfortunately no time to give a complete solution right now, but have a look at class:

org.junit.runners.Suite

Which allows you to call test cases (from any test class) in a specific order.

These might be used to create functional, integration or system tests.

This leaves your unit tests as they are without specific order (as recommended), whether you run them like that or not, and then re-use the tests as part of a bigger picture.

We re-use/inherit the same code for unit, integration and system tests, sometimes data driven, sometimes commit driven, and sometimes run as a suite.

伪装你 2024-09-25 17:42:47

正如其他人所说,理想情况下测试应该独立于执行顺序。这使得测试不那么脆弱,并允许它们独立运行(许多 IDE 允许您选择一个测试方法并独立于其他测试执行它)。

话虽如此,对于集成测试,有些人更喜欢依赖方法排序。

从 JUnit 4.13 开始,您可以通过扩展 订购。有关更多详细信息,请参阅 JUnit wiki。下面是一个使用内置 Alphanumeric 类使用测试方法名称按字母数字顺序对测试进行排序的示例:

import org.junit.Test;
import org.junit.runner.OrderWith;
import org.junit.runner.manipulation.Alphanumeric;

@OrderWith(Alphanumeric.class)
public class TestMethodOrder {

    @Test
    public void testA() {
        System.out.println("first");
    }
    @Test
    public void testB() {
        System.out.println("second");
    }
    @Test
    public void testC() {
        System.out.println("third");
    }
}

As others have stated, tests should be ideally be independent of execution order. This makes tests less fragile, and allows them to be run independently (many IDEs allow you to select a test method and execute it independently of other tests).

That being said, for integration tests, some people prefer to rely on method ordering.

Starting with JUnit 4.13 you can define your own class to reorder tests by extending Ordering. See the JUnit wiki for more details. Here's an example using the built-in Alphanumeric class to order the tests alphanumerically using the test method name:

import org.junit.Test;
import org.junit.runner.OrderWith;
import org.junit.runner.manipulation.Alphanumeric;

@OrderWith(Alphanumeric.class)
public class TestMethodOrder {

    @Test
    public void testA() {
        System.out.println("first");
    }
    @Test
    public void testB() {
        System.out.println("second");
    }
    @Test
    public void testC() {
        System.out.println("third");
    }
}
所谓喜欢 2024-09-25 17:42:47

是时候迁移到 Junit5 了。
以下是我们可以获得的示例:

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
 class OrderedTests {

     @Test
     @Order(1)
     void nullValues() {}

     @Test
     @Order(2)
     void emptyValues() {}

     @Test
     @Order(3)
     void validValues() {}
 }

对于 Junit4,将多个测试中的逻辑复制到一个测试方法中。

It's time to move to Junit5.
Here is a sample of what we could get:

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
 class OrderedTests {

     @Test
     @Order(1)
     void nullValues() {}

     @Test
     @Order(2)
     void emptyValues() {}

     @Test
     @Order(3)
     void validValues() {}
 }

For Junit4, copy the logic that you have in several tests in one test method.

妳是的陽光 2024-09-25 17:42:47

对于 JUnit 4,将此注释放在测试类上解决了问题。

@FixMethodOrder(MethodSorters.JVM)

For JUnit 4, putting this annotation on the test class solved the problem.

@FixMethodOrder(MethodSorters.JVM)
↙厌世 2024-09-25 17:42:47

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

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

您只需注释您的类

@TestMethodOrder(OrderAnnotation.class)

https://junit.org/junit5/docs/current/user-guide/#writing-tests-test-execution-order

我在我的项目中使用它,它效果很好!

With JUnit 5.4, you can specify the order :

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

you just need to annotate your class

@TestMethodOrder(OrderAnnotation.class)

https://junit.org/junit5/docs/current/user-guide/#writing-tests-test-execution-order

i'm using this in my project and it works very well !

孤千羽 2024-09-25 17:42:47

您可以使用以下代码之一:
@FixMethodOrder(MethodSorters.JVM) OR @FixMethodOrder(MethodSorters.DEFAULT) OR @FixMethodOrder(MethodSorters.NAME_ASCENDING)

在您的测试类之前,如下所示:

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class BookTest {...}

You can use one of these piece of codes:
@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 {...}
十秒萌定你 2024-09-25 17:42:47

我读过一些答案,并同意这不是最佳实践,而是排序测试的最简单方法 - JUnit 默认运行测试的方式是按字母名称升序排列。

因此,只需按照您想要的字母顺序命名您的测试即可。另请注意,测试名称必须以开头
与测试这个词。只需注意

test12 将在 test2 之前运行的

数字,因此:

testA_MyFirstTest
testC_ThirdTest
testB_ATestThatRunsSecond

I've read a few answers and agree its not best practice, but the easiest way to order your tests - and the way that JUnit runs tests by default is by alphabetic name ascending.

So just name your tests in the alphabetic order that you want. Also note the test name must begin
with the word test. Just watch out for numbers

test12 will run before test2

so:

testA_MyFirstTest
testC_ThirdTest
testB_ATestThatRunsSecond

不必你懂 2024-09-25 17:42:47

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

Please check out this one: https://github.com/TransparentMarket/junit. It runs the test in the order they are specified (defined within the compiled class file). Also it features a AllTests suite to run tests defined by sub package first. Using the AllTests implementation one can extend the solution in also filtering for properties (we used to use @Fast annotations but those were not published yet).

反目相谮 2024-09-25 17:42:47

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

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

Here is an extension to JUnit that can produce the desired behavior: https://github.com/aafuks/aaf-junit

I know that this is against the authors of JUnit philosophy, but when using JUnit in environments that are not strict unit testing (as practiced in Java) this can be very helpful.

薄暮涼年 2024-09-25 17:42:47

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

我知道这与这个问题并不完全相关,但也许可以帮助找到正确的问题

I ended up here thinking that my tests weren't run in order, but the truth is that the mess was in my async jobs. When working with concurrency you need to perform concurrency checks between your tests as well.
In my case, jobs and tests share a semaphore, so next tests hang until the running job releases the lock.

I know this is not fully related to this question, but maybe could help targeting the correct issue

抚笙 2024-09-25 17:42:47

如果您想在 JUnit 5 中按特定顺序运行测试方法,可以使用以下代码。

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class MyClassTest { 

    @Test
    @Order(1)
    public void test1() {}

    @Test
    @Order(2)
    public void test2() {}

}

If you want to run test methods in a specific order in JUnit 5, you can use the below code.

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class MyClassTest { 

    @Test
    @Order(1)
    public void test1() {}

    @Test
    @Order(2)
    public void test2() {}

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文