我希望按特定顺序执行被标记为 @Test
的测试方法。
例如:
public class MyTest {
@Test public void test1(){}
@Test public void test2(){}
}
我希望每次运行MyTest
时,都能确保在运行test2()
之前先运行test1()
,但我找不到类似于@Test(order=xx)
的注解。
我认为这是JUnit的一个重要功能,如果JUnit的作者不想要有序功能,那么为什么呢?
我希望按特定顺序执行被标记为 @Test
的测试方法。
例如:
public class MyTest {
@Test public void test1(){}
@Test public void test2(){}
}
我希望每次运行MyTest
时,都能确保在运行test2()
之前先运行test1()
,但我找不到类似于@Test(order=xx)
的注解。
我认为这是JUnit的一个重要功能,如果JUnit的作者不想要有序功能,那么为什么呢?
如果您想要移除当前的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");
}
}
@Inherited
,因此在我的AbstractTestCase
父类上变得无效。 - AbVog迁移到TestNG似乎是最好的方式,但我在这里对于jUnit没有找到明确的解决方案。以下是我发现的jUnit中最易读的解决方案/格式:
Migration to 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(){}
}
这样可以确保在第一阶段方法之后、第三阶段方法之前调用第二阶段方法。
注:我认为这种方法比 jUnit 5.5 的 @Order 注释更好,因为它为读者提供了更好的符号表示法。
void stage01_prepareAndTest(){ }
。 - EliuX如果顺序很重要,你应该自己制定顺序。
@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()
是一个简单的函数,它将所有可能的排列迭代到一个数组的集合中。
test2
再次运行 test1
。Junit 可能会在 test1
之前运行 test2
。这很可能不是你想要的结果,也不能回答问题。 - toolforger@TestMethodOrder(OrderAnnotation.class)
和在测试方法上使用@Order(1)
进行排序。@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 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");
}
}
输出:
createUserAndLogin(创建用户并登录)
addItemsInBasket(添加商品到购物篮)
checkoutOrder(结算订单)
顺便说一句,指定@TestMethodOrder(OrderAnnotation.class)
看起来不是必需的(至少在我测试的5.4.0版本中)。
附注
关于问题:使用JUnit 5编写集成测试是否是最佳选择? 我认为这不应该是首要考虑的工具(Cucumber等可能经常为集成测试带来更具体的价值和特性),但在某些集成测试情况下,JUnit框架已经足够了。因此,这是一个好消息,这个功能存在。
这是我在使用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()”的方法开始。
谢谢!@SortMethodsWith
。至少在没有使用它的情况下(在Java 7中,顺序可能非常随机),https://github.com/junit-team/junit/pull/293使排序变得可预测。
public void test*()
的测试方法,而每个测试方法实际上都会成为所属的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()
我不确定我是否同意。如果我想测试“文件上传”,然后测试“由文件上传插入的数据”,为什么我不希望它们彼此独立?我认为完全合理,可以分别运行它们,而不是将两者放在一个Goliath测试用例中。
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
为类进行注释,并保留所有测试方法的@Test
注解,并根据期望的执行顺序按字母顺序重命名它们,例如t1_firstTest()
,t2_secondTest()
等。 - MisterStrickland