2010-05-13 4 views
58

Есть ли какие-либо рекомендации по тому, чтобы Junit выполнял функцию один раз в тестовом файле, и он также не должен быть статическим.Junit before class (non static)

как @BeforeClass на нестационарной функции?

Вот уродливое решение:

@Before void init(){ 
    if (init.get() == false){ 
     init.set(true); 
     // do once block 
    } 
} 

ну это что-то я не хочу делать, и я ищу для комплексного решения JUnit.

+0

Из интереса почему вы пытаетесь это сделать? – Goibniu

+0

Ну, у меня довольно большая иерархия тестовых файлов и базовых тестовых файлов, мне нужно переопределить это действие в классах дочерних тестов. – Roman

+1

У меня была та же проблема, в которой только первый из многих параметризованных тестов должен выполнять логин. – dokaspar

ответ

14

Если вы не хотите, чтобы настроить статические инициализаторы для одной инициализации времени и не особенно об использовании JUnit, посмотрите на TestNG. TestNG поддерживает нестационарную однократную инициализацию с различными параметрами конфигурации, используя аннотации.

В TestNG, это было бы эквивалентно:

@org.testng.annotations.BeforeClass 
public void setUpOnce() { 
    // One time initialization. 
} 

Для демонтажа,

@org.testng.annotations.AfterClass 
public void tearDownOnce() { 
    // One time tear down. 
} 

Для эквивалентной TestNG из JUnit 4-х @Before и @After, вы можете использовать @BeforeMethod и @AfterMethod соответственно.

0

Я никогда не пробовал, но, может быть, вы можете создать конструктор без аргументов и вызвать функцию оттуда?

+0

Это сработает, проблема в том, что мне нужно переопределить это действие в классах, расширяющих этот базовый класс тестов – Roman

+0

@Roman: О, теперь я вижу. Добавьте это в свой пост, этот комментарий делает вещи намного яснее. – Roman

+0

Конструктор будет называться столько раз, сколько есть. Для каждого метода тестирования будет создан новый объект класса Test. Таким образом, использование конструктора здесь не является решением – manikanta

31

Использовать пустой конструктор - это самое простое решение. Вы все равно можете переопределить конструктор расширенного класса.

Но это не оптимально со всем наследованием. Вот почему JUnit 4 использует аннотации.

Другой вариант - создать вспомогательный метод в классе factory/util и позволить этому методу выполнить эту работу.

Если вы используете Spring, вам следует рассмотреть аннотацию @TestExecutionListeners. Что-то вроде этого теста:

@RunWith(SpringJUnit4ClassRunner.class) 
@TestExecutionListeners({CustomTestExecutionListener.class, 
    DependencyInjectionTestExecutionListener.class}) 
@ContextConfiguration("test-config.xml") 
public class DemoTest { 

весны AbstractTestExecutionListener содержит, например, этот пустой метод, который вы можете переопределить:

public void beforeTestClass(TestContext testContext) throws Exception { 
    /* no-op */ 
} 
+0

+1 Этот метод решил мою проблему, когда вы хотите использовать DbUnit и загружать только один набор данных за класс – Brad

+0

+1 Это идеальное решение ... для людей, которые не привязаны к древней версии Весны. :( –

+0

Будет ли этот 'beforeTestClass()' вызываться до или после инициализации контекста? – Dims

28

простой, если заявление, кажется, работает очень хорошо тоже:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = {"classpath:test-context.xml"}) 
public class myTest { 

    public static boolean dbInit = false; 

    @Autowired 
    DbUtils dbUtils; 

    @Before 
    public void setUp(){ 

     if(!dbInit){ 

      dbUtils.dropTables(); 
      dbUtils.createTables(); 
      dbInit = true; 

     } 
    } 

... 
+1

Приятный и простой! Но не вижу способа просто адаптировать это, чтобы сделать нестатический эквивалент '@ AfterClass', который срывается после всех тесты прошли? –

+0

См. [здесь] (http: // stackoverflow.com/questions/12087959/junit-run-set-up-method-once/31117171 # 31117171) для обновления этого метода, который должен работать для тестовых классов, которые используют наследование. –

-1

UPDATE: Пожалуйста, смотрите комментарий вишневыми, почему ниже предложение несовершенна. (Am оставляя ответ, как есть, а не удаление/редактирование, а комментарий может дать полезную информацию для других, почему это не работает.)


Другой вариант стоит рассматривать при использовании инъекции зависимостей (например, весна) составляет @PostConstruct.Эта инъекция будет гарантировать зависимость является полной, что не будет иметь места в конструкторе:

@PostConstruct 
public void init() { 
    // One-time initialization... 
} 
+6

Очень ** плохое ** решение в случае тестов Junit. Junit создает экземпляр класса test каждый раз, когда он запускает тестовый метод. Итак, если в классе 6 методов тестирования, конструктор класса, методы '@ Before' и' @ After' будут называться 6 раз! Поэтому в этом контексте '@ PostConstruct' ведет себя как аннотация @ @ Before. Вы можете просто протестировать его: просто поместите 2 тестовых метода в тестовый класс, добавьте '@PostConstruct public void init() {System.out.println (" start ");}' и просмотрите в журналах, сколько раз оно печатается. – Cherry

+0

Для информации я просто наткнулся на [JUnit documentation] (http://junit.sourceforge.net/javadoc/org/junit/Test.html), который подтверждает то, что описано в комментарии выше о JUnit, создающем экземпляр для каждого '@ Test' run: * «Чтобы запустить метод, JUnit сначала создает новый экземпляр класса, а затем вызывает аннотированный метод». * –

0

The article обсуждают 2 очень хорошие решений для этой проблемы:

  1. «чистый» JUnit с пользовательским Runner (используя интерфейс, но вы можете расширить его с помощью специальной аннотации, например @BeforeInstance)
  2. Слушатели прослушивания Spring, как упоминалось ранее Espen.
-1

Просто используйте @BeforeClass:

@BeforeClass 
public static void init() { 
} 

Это не имеет смысла для init быть не статическую, потому что каждый тест запускается в отдельном экземпляре. Экземпляр , который запущен init, не будет соответствовать экземпляру любого теста.

Единственная причина, по которой вы хотите, чтобы она была нестатической, заключается в переопределении ее в подклассах, но вы можете сделать это со статическими методами. Просто используйте одно и то же имя, и будет вызван только метод подкласса init.

+0

Весь этот вопрос касается возможности сделать это не статическим способом, который необходим, если вам нужны некоторые переменные экземпляра для класса. –

+0

@SimonForsberg Да, и я говорю, что вопрос - проблема XY. Операция сказала, что проблема переопределяет поведение в дочерних классах. Если в примере нужны переменные экземпляра, то я мог бы предложить что-то еще. – fgb

+0

Смотрите этот комментарий: http://stackoverflow.com/questions/2825615/junit-before-class-non-static/27730780?noredirect=1#comment2866266_2825615 –

4

Легко использовать @BeforeAllMethods/@AfterAllMethods аннотации для запуска метода внутри контекста экземпляра (нестатического), где будут доступны все введенные значения.

Существует специальная библиотека тестирования для этого:

https://mvnrepository.com/artifact/org.bitbucket.radistao.test/before-after-spring-test-runner/0.1.0

https://bitbucket.org/radistao/before-after-spring-test-runner/

Единственное ограничение: работает только для Spring тестирования.

(Я являюсь разработчиком этой тестовой библиотеки)

+0

Pls, дайте мне знать, если вы собираетесь использовать библиотеку - я бы хотел, чтобы пользователь мог понять, имеет ли этот проект смысл для сообщества. благодаря – radistao