@BeforeClass и наследование - порядок исполнения
У меня есть базовый базовый класс, который я использую в качестве основы для своих модульных тестов (TestNG 5.10). В этом классе я инициализирую всю среду для своих тестов, настраивая сопоставления баз данных и т.д. Этот абстрактный класс имеет метод с аннотацией @BeforeClass
, который выполняет инициализацию.
Затем я расширяю этот класс с помощью определенных классов, в которых у меня есть методы @Test
, а также методы @BeforeClass
. Эти методы выполняют инициализацию среды, специфичную для класса (например, помещают некоторые записи в базу данных).
Как я могу обеспечить выполнение определенного порядка аннотированных методов @BeforeClass
? Мне нужны те из абстрактного базового класса, который должен быть выполнен до тех, что распространяются в классе.
Пример:
abstract class A {
@BeforeClass
doInitialization() {...}
}
class B extends A {
@BeforeClass
doSpecificInitialization() {...}
@Test
doTests() {...}
}
Ожидаемый заказ:
A.doInitialization
B.doSpecificInitialization
B.doTests
Фактический порядок:
B.doSpecificInitialization // <- crashes, as the base init is missing
(A.doInitialization // <---not executed
B.doTests) // <-/
Ответы
Ответ 1
Не помещайте @BeforeClass
в класс abstract
. Вызовите его из каждого подкласса.
abstract class A {
void doInitialization() {}
}
class B extends A {
@BeforeClass
void doSpecificInitialization() {
super.doInitialization();
}
@Test
void doTests() {}
}
Кажется, что TestNG имеет @BeforeClass(dependsOnMethods={"doInitialization"})
- попробуйте.
Ответ 2
изменить: Нижеприведенный ответ предназначен для JUnit, но я оставлю его здесь в любом случае, потому что это может быть полезно.
В соответствии с JUnit api: "Методы @BeforeClass суперклассов будут выполняться до тех, что относятся к текущему классу".
Я тестировал это, и, похоже, он работает для меня.
Однако, как упоминает @Odys ниже, для JUnit вам нужно иметь два метода по-разному, но, как и в противном случае, будет выполняться только метод подкласса, потому что родитель будет затенен.
Ответ 3
Я добавил public
в абстрактный класс, а TestNG (6.0.1) выполнил doInitialization() до doTests
. TestNG не выполняет doInitialization()
, если я удаляю public
из класса A.
public abstract class A {
@BeforeClass
doInitialization() {...}
}
class B extends A {
@Test
doTests() {...}
}
Ответ 4
Я просто попробовал ваш пример с 5.11, и я сначала вызываю @BeforeClass из базового класса.
Можете ли вы разместить файл testng.xml? Возможно, вы указываете как A, так и B там, в то время как требуется только B.
Не стесняйтесь следить за списком рассылки testng-users, и мы можем более подробно рассмотреть вашу проблему.
-
Седрик
Ответ 5
Я только что прошел через это и нашел еще один способ добиться этого. Просто используйте alwaysRun
в @BeforeClass
или @BeforeMethod
в абстрактном классе, как и следовало ожидать.
public class AbstractTestClass {
@BeforeClass(alwaysRun = true)
public void generalBeforeClass() {
// do stuff
specificBeforeClass();
}
}
Ответ 6
Когда я запускаю из: JUnitCore.runClasses(TestClass.class);
Он правильно выполнит родительский контроль перед ребенком (вам не нужно super.SetUpBeforeClass();).
Если вы запустите его из Eclipse:
По какой-то причине он не может запустить базовый класс.
Работа вокруг:
Вызовите базовый класс явно: (BaseTest.setUpBeforeClass();)
Возможно, вы захотите иметь флаг в базовом классе, если вы запустили его из приложения, чтобы определить, уже ли он настроен или нет. Поэтому он запускается только один раз, если вы запускаете его с помощью обоих возможных методов (например, от eclipse для личного тестирования и через ANT для выпуска сборки).
Это, кажется, ошибка с Eclipse или, по крайней мере, неожиданные результаты.
Ответ 7
Для JUnit:
Как сказал @fortega:
Согласно JUnit api: "Методы @BeforeClass суперклассов будут выполняться до тех, что относятся к текущему классу".
Но будьте осторожны , чтобы не называть оба метода с тем же именем. Поскольку в этом случае родительский метод будет скрыт дочерним родителем. Источник.
Ответ 8
Как насчет того, чтобы ваш метод @BeforeClass вызывал пустой метод specificBeforeClass(), который может или не может быть перезаписан подобными подклассами:
public class AbstractTestClass {
@BeforeClass
public void generalBeforeClass() {
// do stuff
specificBeforeClass();
}
protected void specificBeforeClass() {}
}
public class SpecificTest {
@Override
protected void specificBeforeClass() {
// Do specific stuff
}
// Tests
}
Ответ 9
dependsOnMethod
.
например. в случае Spring (AbstractTestNGSpringContextTests
)
@BeforeClass(alwaysRun = true, dependsOnMethods = "springTestContextPrepareTestInstance")
Ответ 10
Проверьте свое выражение на импорт. Так должно быть
import org.testng.annotations.BeforeClass;
не
import org.junit.BeforeClass;
Ответ 11
Почему бы вам не попытаться создать абстрактный метод doSpecialInit() в вашем суперклассе, вызванный из аннотированного метода BeforeClass в суперклассе.
Таким образом, разработчики, наследующие ваш класс, вынуждены реализовать этот метод.
Ответ 12
Здесь есть еще одно простое решение.
Моя особая ситуация заключается в том, что мне нужно вводить макеты с "BeforeClass" в подкласс до того, как выполняется "BeforeClass" в суперклассе.
Для этого просто используйте @ClassRule
в подклассе.
Например:
@ClassRule
public static ExternalResource mocksInjector = new ExternalResource() {
@Override
protected void before() {
// inject my mock services here
// Note: this is executed before the parent class @BeforeClass
}
};
Надеюсь, это поможет. Это может эффективно выполнить статическую настройку в обратном порядке.
Ответ 13
Я столкнулся с подобной проблемой сегодня, единственное отличие было в том, что базовый класс не был
Вот мой случай
public class A {
@BeforeClass
private void doInitialization() {...}
}
public class B extends A {
@BeforeClass
private void doSpecificInitialization() {...}
@Test
public void doTests() {...}
}
@BeforeClass
метод @BeforeClass
из класса A никогда не выполнялся.
- A.doInitialization() → ЭТО БЫЛО НИКОГДА НЕ ВЫПОЛНЕНО
- B.doSpecificInitialization()
- B.doTests()
Играя с модификаторами конфиденциальности, я обнаружил, что TestNG не будет выполнять аннотированный метод @BeforeClass
из унаследованного класса, если метод не виден из класса-наследника
Так что это будет работать:
public class A {
@BeforeClass
private void doInitialization() {...}
}
public class B extends A {
@BeforeClass
//Here a privacy modifier matters -> please make sure your method is public or protected so it will be visible for ancestors
protected void doSpecificInitialization() {...}
@Test
public void doTests() {...}
}
В результате происходит следующее:
- A.doInitialization()
- B.doSpecificInitialization()
- B.doTests()
Ответ 14
Это работает для меня -
abstract class A {
@BeforeClass
doInitialization() {...}
}
class B extends A {
@Override
@BeforeClass
doInitialization() {
//do class specific init
}
@Test
doTests() {...}
}
Ответ 15
В моем случае (JUnit) у меня есть те же методы, что и setup() в базовом классе и производном классе. В этом случае вызывается только метод производного класса, и я вызываю метод базового класса.
Ответ 16
Лучшим и более чистым способом достижения этого с помощью наследования может быть следующее:
abstract class A {
@BeforeClass
void doInitialization() {}
}
class B extends A {
@Override
@BeforeClass
void doInitialization() {
super.doInitialization();
}
@Test
void doTests() {}
}