Junit - несколько @Before против одного @перед разделением на методы
В unit test мне нужно выполнить довольно сложную настройку (это может быть запах кода, но это не тот вопрос, о котором идет речь:-)). Я заинтересован в том, что лучше иметь несколько методов @Before
, выполняющих установку, или только один, который вызывает вспомогательные методы для выполнения инициализации.
например.
@Before
public void setUpClientStub() {
}
@Before
public void setUpObjectUnderTest() {
}
против.
@Before
public void setUp() {
setUpClientStub();
setUpObjectUnderTest();
}
Ответы
Ответ 1
Как было сказано в других ответах, порядок, в котором JUnit находит методы, не гарантируется, поэтому порядок @Before
методов @Before
не может быть гарантирован. То же самое относится к @Rule
, он страдает от такой же гарантии. Если это всегда будет один и тот же код, тогда нет никакой разницы в двух методах.
Если у вас есть два метода, и что более важно, если вы хотите использовать их из нескольких мест, тогда вы можете комбинировать правила, используя RuleChain, который был введен в 4.10. Это позволяет задать порядок правил, например:
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()
Ответ 2
Я бы сделал последнее. AFAIK, нет способа гарантировать порядок @Before аннотированных методов настройки.
Ответ 3
Обратите внимание, что нет никаких гарантий относительно порядка, в котором вызывается @Before
аннотированные методы. Если между ними есть некоторые зависимости (например, один метод должен быть вызван перед другим), вы должны использовать последнюю форму.
В противном случае это вопрос предпочтения, просто держите их в одном месте, чтобы их было легко обнаружить.
Ответ 4
Я не думаю, что это имеет большое значение, но я лично предпочитаю второй (порядок до того, как методы выполняются не определены, у вас будет лучший контроль таким образом).
Ответ 5
Для меня это похоже на использование JUnit 4.12
, методы, аннотированные с помощью @Before
действительно детерминистически сортируются по следующему @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
выполнил ваши задачи настройки в правильном порядке.
Хотя вышеупомянутый подход возможен, я думаю, вы не должны делать этого в своих тестах, потому что Java-Annotations в JUnit была введена, чтобы уйти от тестирования на основе конвенций.