@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) // <-/
14 ответов:
не поставить
@BeforeClassнаabstractкласса. Вызовите его из каждого подкласса.abstract class A { void doInitialization() {} } class B extends A { @BeforeClass void doSpecificInitialization() { super.doInitialization(); } @Test void doTests() {} }похоже, что TestNG имеет
@BeforeClass(dependsOnMethods={"doInitialization"})- дать ему попробовать.
edit: Ответ ниже для JUnit, но я оставлю его здесь в любом случае, потому что это может быть полезно.
по словам JUnit api: "методы @ BeforeClass суперклассов будут выполняться перед текущим классом."
Я проверил это, и это, кажется, работает для меня.
однако, как @Odys упоминает ниже, для JUnit вам нужно иметь два метода с разными именами Как делать в противном случае будет выполняться только метод подкласса, потому что родитель будет затенен.
Я только что попробовал ваш пример с 5.11 и я получаю @BeforeClass базового класса вызывается первым.
можете ли вы опубликовать свой testng.xml-файл? Может быть, вы указываете и A и B там, в то время как только B необходимо.
Не стесняйтесь следить за списком рассылки testng-users, и мы можем более подробно рассмотреть вашу проблему.
-- Седрик
добавил
publicк абстрактному классу и TestNG (6.0.1) выполнил doInitialization () передdoTests. TestNG не выполняетdoInitialization()Если я удалитьpublicиз класса А.public abstract class A { @BeforeClass doInitialization() {...} } class B extends A { @Test doTests() {...} }
Я только что прошел через это и нашел еще один способ достичь этого. Просто используйте
alwaysRunon@BeforeClassили@BeforeMethodв абстрактном классе работает так, как вы ожидаете.public class AbstractTestClass { @BeforeClass(alwaysRun = true) public void generalBeforeClass() { // do stuff specificBeforeClass(); } }
Как насчет того, чтобы ваш метод @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 }
когда я бегу от:JUnitCore.runClasses (TestClass.класс); Он будет выполнять родителя правильно, перед ребенком (вам не нужно супер.SetUpBeforeClass ();) Если запустить его из Eclipse: По какой-то причине он не может запустить базовый класс. Работы по: Вызовите базовый класс явно: (BaseTest.setUpBeforeClass ();) Вы можете иметь флаг в базовом классе в случае запуска его из приложения, чтобы определить, если он уже настроен или не. Таким образом, он запускается только один раз, если вы запускаете его с помощью обоих возможных методов (например, из eclipse для личного тестирования и через ANT для выпуска сборки).
Это похоже на ошибку с Eclipse или, по крайней мере, неожиданные результаты..
Для JUnit: Как упоминал @fortega: Согласно JUnit api: "методы @ BeforeClass суперклассов будут запускаться перед тем, как текущий класс."
но будьте осторожны не называть оба метода с одинаковым именем. Так как в этом случае родительский метод будет скрыт дочерним родителем. источник.
dependsOnMethodможно использовать.например, в случае пружины (
AbstractTestNGSpringContextTests)@BeforeClass(alwaysRun = true, dependsOnMethods = "springTestContextPrepareTestInstance")
Проверьте инструкцию импорта. Он должен быть!--3-->
import org.testng.annotations.BeforeClass;не
import org.junit.BeforeClass;
Почему бы вам не попробовать создать абстрактный метод doSpecialInit() в вашем суперклассе, вызываемый из вашего аннотированного метода BeforeClass в суперклассе.
поэтому разработчики, наследующие ваш класс, вынуждены реализовать этот метод.
здесь есть еще одно простое решение.
моя конкретная ситуация заключается в том, что мне нужно ввести фиктивные сервисы из "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 } };Я надеюсь, что это помогает. Это может эффективно выполнять статическую настройку в" обратном " порядке.
в моем случае (JUnit) у меня есть те же методы, которые называются setup () в базовом классе и производном классе. В данном случае только вызывается метод производного класса, и у меня он вызывает метод базового класса.
лучший и более чистый способ достичь этого с помощью наследования может быть следующим -
abstract class A { @BeforeClass void doInitialization() {} } class B extends A { @Override @BeforeClass void doInitialization() { super.doInitialization(); } @Test void doTests() {} }
Comments