Подтвердить что ты не робот

Junit - запустить метод настройки один раз

Я создал класс с несколькими тестами и вместо использования @Before Я хотел бы иметь метод установки, который выполняется только один раз перед всеми тестами. Возможно ли это с Junit 4.8?

4b9b3361

Ответ 1

Хотя я согласен с @assylias, что использование @BeforeClass является классическим решением, но это не всегда удобно. Метод, аннотированный @BeforeClass должен быть статическим. Это очень неудобно для некоторых тестов, которые требуют экземпляра контрольного примера. Например, тесты на основе Spring, которые используют @Autowired для работы со службами, определенными в контексте Spring.

В этом случае я лично использую обычный setUp() @Before аннотацией @Before и управляю своим собственным static (!) boolean флагом:

private static boolean setUpIsDone = false;
.....
public void setUp() {
    if (setUpIsDone) {
        return;
    }
    // do the setup
    setUpIsDone = true;
}

Ответ 2

Вы можете использовать аннотацию BeforeClass:

@BeforeClass
public static void setUpClass() {
    //executed only once, before the first test
}

Ответ 3

JUnit 5 теперь имеет @BeforeAll аннотацию:

Обозначает, что аннотированный метод должен быть выполнен до всех @Test методы в текущей иерархии классов или классов; аналогично JUnit 4s @BeforeClass. Такие методы должны быть статическими.

Аннотации жизненного цикла JUnit 5, похоже, наконец-то поняли! Вы можете угадать, какие аннотации доступны, даже не глядя (например, @BeforeEach @AfterAll)

Ответ 4

Когда setUp() находится в суперклассе тестового класса, принятый ответ может быть изменен следующим образом:

public abstract class AbstractTestBase {
    private static Class<? extends AbstractTestBase> testClass;
    .....
    public void setUp() {
        if (this.getClass().equals(testClass)) {
            return;
        }

        // do the setup - once per concrete test class
        .....
        testClass = this.getClass();
    }
}

Это должно работать для одного нестатического setUp() но я не могу произвести эквивалент для tearDown() не отклоняясь в мир сложных отражений... Щедрость указывает любому, кто может!

Ответ 5

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

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

public UT () {
    // initialize once here
}
@Test
// Some test here...

ctor будет вызван перед тестами, потому что они не являются статическими.

Ответ 6

Попробуйте это решение: fooobar.com/questions/81653/...:

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

Ответ 7

Мое грязное решение:

public class TestCaseExtended extends TestCase {

    private boolean isInitialized = false;
    private int serId;

    @Override
    public void setUp() throws Exception {
        super.setUp();
        if(!isInitialized) {
            loadSaveNewSerId();
            emptyTestResultsDirectory();
            isInitialized = true;
        }
    }

   ...

}

Я использую его как базовую базу для всех моих тестовых случаев.

Ответ 8

Если вы не хотите принудительно объявлять переменную, которая устанавливается и проверяется в каждом подтесте, то добавление этого в SuperTest может сделать:

public abstract class SuperTest {

    private static final ConcurrentHashMap<Class, Boolean> INITIALIZED = new ConcurrentHashMap<>();
    protected final boolean initialized() {
        final boolean[] absent = {false};
        INITIALIZED.computeIfAbsent(this.getClass(), (klass)-> {
            return absent[0] = true;
        });
        return !absent[0];
    }
}



public class SubTest extends SuperTest {
    @Before
    public void before() {
        if ( super.initialized() ) return;

         ... magic ... 
    }

}

Ответ 9

Я решил эту проблему так:

Добавьте к своему базовому абстрактному классу (я имею в виду абстрактный класс, где вы инициализируете свой драйвер в методе setUpDriver()) эту часть кода:

private static boolean started = false;
static{
    if (!started) {
        started = true;
        try {
            setUpDriver();  //method where you initialize your driver
        } catch (MalformedURLException e) {
        }
    }
}

И теперь, если ваши тестовые классы простираются от базового абстрактного класса → метод setUpDriver() будет выполняться до первого @Test только ОДИН раз за цикл.

Ответ 10

Вы можете использовать JUnit 5, который представил аннотации @BeforeAll и @TestInstance.

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

Вот фрагмент:

@TestInstance(value = TestInstance.Lifecycle.PER_CLASS)
public class ExampleTest  {

    @Autowired
    private MyRepository myRepository;

    @BeforeAll
    public void setUp() {
       //use injected beans here
    }

Согласно документации:

/** * При использовании этого режима новый экземпляр теста будет создаваться один раз для каждого класса теста. * * @see #PER_METHOD */PER_CLASS

Следовательно, класс будет создан один раз, и не будет необходимости использовать статический метод.