39

我知道这是不好的做法,但需要这样做,否则我需要切换到testng. 有没有一种类似于 JUnit 3 的 testSuite 的方法来指定要在一个类中运行的测试的顺序?

4

6 回答 6

62

如果你确定你真的想这样做:可能有更好的方法,但这就是我能想出的全部......

JUnit4 有一个注解:@RunWith它允许您覆盖测试的默认 Runner。

在您的情况下,您希望创建一个特殊的子类BlockJunit4ClassRunner,并覆盖computeTestMethods()以按照您希望它们执行的顺序返回测试。例如,假设我想按字母倒序执行我的测试:

public class OrderedRunner extends BlockJUnit4ClassRunner {

    public OrderedRunner(Class klass) throws InitializationError {
        super(klass);
    }

    @Override
    protected List computeTestMethods() {
        List list = super.computeTestMethods();
        List copy = new ArrayList(list);
        Collections.sort(copy, new Comparator() {
            public int compare(FrameworkMethod o1, FrameworkMethod o2) {
                return o2.getName().compareTo(o1.getName());
            }
        });
        return copy;
    }
}
@RunWith(OrderedRunner.class)
public class OrderOfTest {
    @Test public void testA() { System.out.println("A"); }
    @Test public void testC() { System.out.println("C"); }
    @Test public void testB() { System.out.println("B"); }
}

运行此测试会产生:

C
乙
一个

对于您的特定情况,您需要一个比较器,它可以按照您希望它们执行的顺序按名称对测试进行排序。(我建议使用类似 Google Guava 的类来定义比较器Ordering.explicit("methodName1","methodName2").onResultOf(...);,其中 onResultOf 提供了一个将 FrameworkMethod 转换为其名称的函数......尽管显然你可以自由地以任何你想要的方式实现它。

于 2010-09-02T03:37:30.117 回答
62

我可以看到这样做的几个原因,尤其是在使用 JUnit 运行功能测试或测试持久对象时。例如,考虑一个Article持久化到某种持久存储的对象。如果我想Article按照单元测试原则“所有测试都应该是可重新排序的并且只测试功能的特定部分”来测试对象上的插入、更新和删除功能,我将进行三个测试:

  • testInsertArticle()
  • testUpdateArticle()
  • testDeleteArticle()

但是,为了能够测试更新功能,我首先需要插入文章。为了测试删除功能,我还需要插入一篇文章。因此,在实践中,插入功能已经在testUpdateArticle()和中进行了测试testDeleteArticle()。然后很想创建一个testArticleFunctionality()可以完成所有工作的测试方法,但是这样的方法最终会变得很大(并且它们不会只测试Article对象的部分功能)。

对例如 restful API 运行功能测试也是如此。如果不是因为不确定的测试顺序,JUnit 也适用于这些情况。

也就是说,我扩展了 Michael DOrderedRunner以使用注释来确定测试顺序,只是认为我应该分享。它可以进一步扩展,例如通过准确指定每个测试所依赖的测试,但这是我现在使用的。

这就是它的使用方式。它避免了命名测试的需要,如AA_testInsert(), AB_testUpdate(), AC_testDelete(), ...,ZC_testFilter()等。

@RunWith(OrderedRunner.class)
public class SomethingTest {
    @Test
    @Order(order=2)
    public void testUpdateArticle() {
        // test update
    }

    @Test
    @Order(order=1)
    public void testInsertArticle() {
        // test insert
    }

    @Test
    @Order(order=3)
    public void testDeleteArticle() {
        // test delete
    }
}

无论这些测试如何放置在文件中,它们将始终作为order=1first、order=2second 和 lastorder=3运行,无论您是从 Eclipse 内部、使用 Ant 还是任何其他方式运行它们。

实施如下。首先,注释Order

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

然后,修改后的OrderedRunner.

public class OrderedRunner extends BlockJUnit4ClassRunner {
    public OrderedRunner(Class<?> klass) throws InitializationError {
        super(klass);
    }

    @Override
    protected List<FrameworkMethod> computeTestMethods() {
        List<FrameworkMethod> copy = new ArrayList<>(super.computeTestMethods());
        Collections.sort(list, 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 0;
                if (o1 == null) return 1;
                if (o2 == null) return -1;

                return o1.order() - o2.order();
            }
        });
        return list;
    }
}
于 2012-09-07T15:05:39.400 回答
26

从 JUnit 4.11 版开始,可以通过使用@FixMethodOrder和指定任何可用的MethodSorters. 有关更多详细信息,请参阅链接。

于 2013-02-02T18:33:55.910 回答
4

使用junit 4.11注释 @FixMethodOrder允许设置特定顺序:

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
于 2014-03-20T16:08:24.363 回答
1

如果您想按“就像它们出现在您的源代码中一样”的顺序运行 junit 测试,并且不想修改您的测试代码,请在此处查看我的注释:

如何按照它们在源代码中的顺序运行junit测试

但这确实不是一个好主意,测试必须是独立的。

于 2012-11-12T10:54:55.267 回答
1

Joscarsson 和 Michael D 代码在我的 github 存储库中。我希望他们不介意。我还为参数化类提供了有序版本。它已经用作 maven 依赖项

<repositories>
    <repository>
        <id>git-xxx</id>
        <url>https://github.com/crsici/OrderedRunnerJunit4.11/raw/master/</url>
    </repository>
</repositories>

<dependency>
    <groupId>com.sici.org.junit</groupId>
    <artifactId>ordered-runner</artifactId>
    <version>0.0.1-RELEASE</version>
</dependency>
于 2015-07-24T09:16:54.423 回答