@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) // <-/
639   14  

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() {...}
}

Я только что прошел через это и нашел еще один способ достичь этого. Просто используйте alwaysRun on @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

    Ничего не найдено.