2013-11-06 2 views
0

У меня есть то, что составляет легкую тестовую структуру, написанную как JUnit Abstract test. Я бы хотел, чтобы каждый из подклассов реализации определял их собственную настройку тестового класса. Мой план состоял в том, чтобы абстрактный суперкласс определял метод @BeforeClass, который вызывает абстрактный метод настройки, который каждый подкласс должен был бы определить, но это не так, поскольку методы @BeforeClass должны быть статическими, а статические методы не могут быть абстрактными и не могут вызвать экземпляр методы.Обеспечение того, что тест подкласса JUnit переопределяет метод @BeforeClass

Я мог бы просто предположить, что подклассы будут выполнять настройку, включив то, что требуется в документации, или бросая IllegalStateException, но мне бы очень хотелось, чтобы это можно было обеспечить на уровне интерфейса по ряду причин. Может ли кто-нибудь подумать об этом?

Кстати, у меня была та же проблема с параметризацией этих тестов (подклассы определяют параметры, но @Parameters аннотированные методы должны быть статическими). Я обошел это, работая с третьей стороной JUnitParams, которая позволяет параметры уровня метода. Посмотрите здесь: https://github.com/Pragmatists/JUnitParams

+0

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

+1

Только один раз с каждым тестовым классом. Я могу запустить его для каждого метода тестирования, используя @Before, но это было бы расточительно. – user1919883

ответ

1

Один из вариантов заключается в том, чтобы подклассы реализовали, скажем, статический метод doSetupOnce(), и нашли и вызвали этот метод рефлексивно из метода базового класса @BeforeClass. Поскольку это должен быть статический метод, его существование может быть применено только во время выполнения.

Другим подходом было бы иметь метод экземпляра doSetupOnce в базовом классе, который вызывается при первом вызове метода родителя @Before. Это приводит к возникновению проблемы во время компиляции, но тогда разработчики должны быть осторожны, чтобы не получить доступ к полям экземпляра из этого метода (поскольку это, вероятно, не то, что они хотят).

В целом (и не зная подробностей вашей ситуации), я не очень люблю этот подход и предпочел бы оставить его разработчикам для объявления метода @BeforeClass, если это необходимо. Блокировка их в жесткой схеме базового класса может вызвать больше проблем, чем решает. Также рассмотрите использование правил JUnit, которые часто являются лучшим выбором, чем базовые классы (например, поскольку они являются составными). Конечно, вы также можете объединить два подхода, полагаясь главным образом на правила JUnit и дополнительно предлагая некоторые базовые классы с предопределенными правилами для удобства.

+0

Спасибо, мне очень нравится ваше среднее решение, которое соответствует моим целям. Я согласен с тем, что это делает тест немного жестким и немного запах, но эти тесты таковы, что они требуют ALOT настройки, а затем выполняют небольшое количество фактического тестового кода. Я еще раз взгляну на правила JUnit, поскольку я только знаком с ними. – user1919883

1

Для вашего основного вопроса, почему бы не сделать абстрактный родительский класс и использовать @Before аннотацию вместо @BeforeClass? Например:

public abstract class TestParent { 
    @Before 
    public void setup() { 
    doSetup(); 
    } 

    protected abstract void doSetup(); 

    // other stuff... 
} 

public class RealTest extends TestParent { 
    protected void doSetup() { 
     // custom setup 
    } 

    // custom tests... 
} 

Это заставит подклассов переопределить метод doSetup() без использования статических методов.

+2

'@ BeforeClass' будет выполняться только один раз, когда' @ Before' будет выполняться до каждого теста – dkatzel

+0

Точно. Я хочу, чтобы установка была однажды. @ Прежде, чем произойдет каждый метод тестирования. – user1919883

+1

Насколько я понимаю, ваш вопрос. Для такой ситуации вы можете использовать отражение в методе родительского класса @BeforeClass, чтобы проверить существование вашего подкласса статический «обычный» метод: если он существует, вызовите его, если не выбросите какое-то исключение. –

1

Это может быть вне сферы действия или излишнего, но я думаю, что стоит упомянуть, так как они не такие разные. Поэтому я беру скачок веры и предлагаю вам попробовать TestNG, потому что методы, аннотированные с помощью @BeforeClass, не обязательно должны быть статичными, а также аннотированы с помощью @Parameters.

Вы можете прочитать о различиях между 2 рамками here и, похоже, они также имеют поддержку migrating JUnit tests to TestNG

1

Я не думаю, что это возможно сделать это в чистом OO пути. Не только @BeforeClass статический метод, но JUnit будет вызывать родительский @BeforeClass до @BeforeClass ребенка.

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

Я думаю, что лучший способ - использовать @Before, но также иметь статический флаг, который устанавливает, если метод был вызван раньше, таким образом, по крайней мере, вы можете короткозамкнуто и выполнять инициализацию только для первого вызова. ..

Смежные вопросы