在单元测试中,我需要执行一个相当复杂的设置(这可能是代码味道,但这不是这个问题的内容:-))。我感兴趣的是,如果最好有多个@Before
方法执行设置或只有一个,它调用辅助方法来执行初始化。
E.g。
@Before
public void setUpClientStub() {
}
@Before
public void setUpObjectUnderTest() {
}
VS
@Before
public void setUp() {
setUpClientStub();
setUpObjectUnderTest();
}
答案 0 :(得分:31)
正如在其他响应中所述,JUnit找到方法的顺序无法保证,因此无法保证@Before
方法的执行顺序。 @Rule
也是如此,它同样缺乏保证。如果这将始终是相同的代码,那么分成两个方法没有任何意义。
如果你有两种方法,更重要的是,如果你想在多个地方使用它们,那么你可以使用4.10中引入的RuleChain来组合规则。这允许规则的特定顺序,例如:
public static class UseRuleChain {
@Rule
public TestRule chain= RuleChain
.outerRule(new LoggingRule("outer rule"))
.around(new LoggingRule("middle rule"))
.around(new LoggingRule("inner rule"));
@Test
public void example() {
assertTrue(true);
}
}
这会产生:
starting outer rule
starting middle rule
starting inner rule
finished inner rule
finished middle rule
finished outer rule
所以你可以升级到4.10或者只是偷走课程。
在您的情况下,您可以定义两个规则,一个用于客户端设置,一个用于对象,并将它们组合在RuleChain
中。使用ExternalResource。
public static class UsesExternalResource {
private TestRule clientRule = new ExternalResource() {
@Override
protected void before() throws Throwable {
setupClientCode();
};
@Override
protected void after() {
tearDownClientCode()
};
};
@Rule public TestRule chain = RuleChain
.outerRule(clientRule)
.around(objectRule);
}
所以你将拥有以下执行顺序:
clientRule.before()
objectRule.before()
the test
objectRule.after()
clientRule.after()
答案 1 :(得分:7)
我会做后者。 AFAIK,无法保证@Before带注释的设置方法的顺序。
答案 2 :(得分:4)
请注意,无法保证调用@Before
带注释的方法的顺序。如果它们之间存在某些依赖关系(例如,必须在另一个方法之前调用一个方法),则必须使用后一种形式。
否则这是一个偏好的问题,只需将它们放在一个地方,这样就很容易发现它们。
答案 3 :(得分:3)
我认为它没有多大区别,但我个人更喜欢第二种方法(方法执行之前的顺序没有定义,你会有更好的控制方式)。
答案 4 :(得分:0)
对我来说,似乎使用JUnit 4.12
,用@Before
注释的方法确实通过以下特征进行了确定性的确定确定:
按相反的字典顺序(相对于方法名称)。
您可以通过执行以下Testclass来查看此行为:
import java.util.Arrays;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
/*
* key points:
* - multiple @Before methods get sorted by reversed lexicographic order
* */
public class JUnitLifecyle {
@BeforeClass
public static void runsOnceBeforeClassIsInited() {
System.out.println("@BeforeClass");
}
public JUnitLifecyle() {
System.out.println("Constructor");
}
@Before
public void a() {
System.out.println("@Before a");
}
@Before
public void b() {
System.out.println("@Before b");
}
@Before
public void cd() {
System.out.println("@Before cd");
}
@Before
public void ca() {
System.out.println("@Before ca");
}
@Before
public void cc() {
System.out.println("@Before cc");
}
@Before
public void d() {
System.out.println("@Before d");
}
@Before
public void e() {
System.out.println("@Before e");
}
@Test
public void firstTest() {
System.out.println("@Test 1");
}
@Test
public void secondTest() {
System.out.println("@Test 2");
}
@After
public void runsAfterEveryTestMethod() {
System.out.println("@After");
}
@AfterClass
public static void runsOnceAfterClass() {
System.out.println("@AfterClass");
}
}
我在处理输出之后,更改了用@Before
注释的方法的方法名称,得出了这个结论。
请牢记颠倒的字典顺序,您可以相应地命名方法,以使JUnit
以正确的顺序执行设置任务。
尽管可以采用上述方法,但是我认为您不应在测试中这样做,因为JUnit中引入了Java-Annotations来摆脱基于约定的测试。
答案 5 :(得分:0)
我将我的所有@Before方法声明为私有,并创建了一个用@Before注释的方法,该方法调用了所有这些方法,并且我的测试有效。我在科特林工作过。 这是您的操作方法:
private fun setUpClientStub() {
//whatever you want to do
}
private fun setUpObjectUnderTest() {
//whatever you want to do
}
@Before
fun setUp() {
setUpClientStub()
setUpObjectUnderTest()
}
@Test
fun test() {
//your test logic
}
这样,您可以确保以正确的顺序调用方法,并且可以根据需要命名它们。