@Beforclass и наследство - Порядок исполнения
-
22-09-2019 - |
Вопрос
У меня есть абстрактный базовый класс, который я использую в качестве базы для своих модульных тестов (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) // <-/
Решение
Не ставит @BeforeClass
на abstract
учебный класс. Назовите это из каждого подкласса.
abstract class A {
void doInitialization() {}
}
class B extends A {
@BeforeClass
void doSpecificInitialization() {
super.doInitialization();
}
@Test
void doTests() {}
}
Похоже, что Testng @BeforeClass(dependsOnMethods={"doInitialization"})
- попробуйте.
Другие советы
редактировать: Ответ ниже для Юнит, но я все равно оставлю это здесь, потому что это может быть полезно.
Согласно JUNIT API: «Методы SuperClass @beforclass будут запущены перед теми текущим классом».
Я проверил это, и, кажется, это работает для меня.
Однако, как упоминает @odys ниже, для JUNIT вам нужно иметь Два метода назвали по -разному хотя, как иначе приведет только к запуску только подкласса, потому что родитель будет затенен.
я добавил public
к абстрактному классу и тестированию (6.0.1) выполнили doInitialization () до doTests
. Анкет Testng не выполняет doInitialization()
Если я удалюсь public
Из класса А.
public abstract class A {
@BeforeClass
doInitialization() {...}
}
class B extends A {
@Test
doTests() {...}
}
Я только что попробовал ваш пример с 5.11 и сначала получу @beforeclass базового класса.
Можете ли вы опубликовать свой файл testng.xml? Может быть, вы указываете там и A, и B, в то время как только B необходим.
Не стесняйтесь следить за почтовым списком Testng-Users, и мы можем более внимательно рассмотреть вашу проблему.
- Седрик
Я только что прошел через это и нашел еще один способ достичь этого. Просто используйте alwaysRun
на @BeforeClass
или же @BeforeMethod
В абстрактном классе работает, как и следовало ожидать.
public class AbstractTestClass {
@BeforeClass(alwaysRun = true)
public void generalBeforeClass() {
// do stuff
specificBeforeClass();
}
}
Когда я бегу от: Junitcore.runclases (testclass.class);Он будет выполнять родителя должным образом, перед ребенком (вам не нужно super.setupbeforeClass ();) Если вы запустите его из Eclipse: по какой -то причине он не может запустить базовый класс. Работа: Позвоните в базовый класс явно: (Basetest.setupbeforeClass ();) Вы можете иметь флаг в базовом классе, если вы запустите его из приложения, чтобы определить, уже настроен или нет. Таким образом, он работает только один раз, если вы запускаете его оба возможных метода (например, от Eclipse для личного тестирования и через ANT для выпуска сборки).
Похоже, это ошибка с затмением или, по крайней мере, неожиданные результаты.
Для Юнита: Как упоминал @Fortega: согласно API JUNIT: «Методы суперкладов @beforclass будут запущены перед теми текущим классом».
Но будь осторожен не называть оба метода с одинаковым именем. Анкет Поскольку в этом случае родительский метод будет скрыт родителем -ребенком. Источник.
Как насчет того, чтобы ваш метод @beforeClass вызовит пустой метод конкретного beaforeClass (), который может быть или не быть перезаписан подзадаченными классами, такими как SO:
public class AbstractTestClass {
@BeforeClass
public void generalBeforeClass() {
// do stuff
specificBeforeClass();
}
protected void specificBeforeClass() {}
}
public class SpecificTest {
@Override
protected void specificBeforeClass() {
// Do specific stuff
}
// Tests
}
dependsOnMethod
может быть использован.
например, в случае весны (AbstractTestNGSpringContextTests
)
@BeforeClass(alwaysRun = true, dependsOnMethods = "springTestContextPrepareTestInstance")
Проверьте свой импорт. Так должно быть
import org.testng.annotations.BeforeClass;
нет
import org.junit.BeforeClass;
Почему бы вам не попытаться создать абстрактный метод dospecialinit () в вашем супер классе, называемый из вашего аннотированного метода BeForeClass в SuperClass.
Таким образом, разработчики, унаследовавшие ваш класс, вынуждены реализовать этот метод.
Здесь есть еще одно простое решение.
Моя особая ситуация заключается в том, что мне нужно вводить фиктивные услуги из «beforeclass» в подкласс, прежде чем «beforeclass» в Superclass выполняется.
Для этого - просто используйте @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
}
};
Надеюсь, это поможет. Это может эффективно выполнить статическую настройку в «обратном» порядке.
Сегодня я столкнулся с аналогичной проблемой, единственное отличие было базовым классом, не было абстрактным
Вот мой случай
public class A {
@BeforeClass
private void doInitialization() {...}
}
public class B extends A {
@BeforeClass
private void doSpecificInitialization() {...}
@Test
public void doTests() {...}
}
Пришло в голову, что @BeforeClass
Метод из класса A никогда не был выполнен.
- A.Doinitialization () -> Это никогда не выполнялось молча
- B.доспецифичинициализация ()
- 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.доспецифичинициализация ()
- B.dotests ()
Это работает для меня -
abstract class A {
@BeforeClass
doInitialization() {...}
}
class B extends A {
@Override
@BeforeClass
doInitialization() {
//do class specific init
}
@Test
doTests() {...}
}
В моем случае (JUNIT) у меня есть те же методы, называемые setup () в базовом классе и полученный класс. В таком случае Только Метод полученного класса называется, и я могу вызвать метод базового класса.
Лучший и более чистый способ достижения этого с использованием наследования может быть связано с следующим -
abstract class A {
@BeforeClass
void doInitialization() {}
}
class B extends A {
@Override
@BeforeClass
void doInitialization() {
super.doInitialization();
}
@Test
void doTests() {}
}