TestNG: Соавторы, локальные для теста

Предположим, у меня есть один тестовый класс с тремя тестовыми методами. Тесты могут выполняться либо последовательно, либо в двух отдельных потоках. Для каждого метода тестирования требуется собственный экземпляр соавтора (например, какой-либо ресурс). Тем не менее, это, казалось бы, не сокращает его:

public class MyTestClass {
    private Resource resource;

    @BeforeMethod public void setupResource() {}
    @AfterMethod public void tearDownResource() {}

    @Test public void testMethod1() {}
    @Test public void testMethod2() {}
    @Test public void testMethod3() {}
}

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

Итак, как насчет этого:

public class MyTestClass {
    private static ThreadLocal<Resource> resource;

    @BeforeMethod public void setupResource() {}
    @AfterMethod public void tearDownResource() {}

    @Test public void testMethod1() {}
    @Test public void testMethod2() {}
    @Test public void testMethod3() {}
}

Это кажется правдоподобным, и похоже, что он может устареть, если я добавлю @DataProvider и тестовые слушатели (при условии, что setupResource() и tearDownResource() правильно реализованы, так что, если есть два потока для запуска тестов, третий метод не имеет любые «остатки» от первого).

Сказав это, кажется довольно громоздким иметь @BeforeMethod, @AfterMethod и обертывать соавтора (Resource) в ThreadLocal. Есть ли какие-либо другие достойные внимания альтернативы «тестового местного»?


person Kelvin Chung    schedule 21.08.2014    source источник


Ответы (1)


Я думаю, вы можете настроить контейнер threadlocal отдельно. Что-то вроде ниже; создайте класс контейнера Mythreadlocal.

public class ThreadLocalContextObject{
  private Resource resource;
  // getter and setter for above
}

public class MyThreadLocal {
  public static final ThreadLocal threadLocal = new ThreadLocal();

  public static void set(ThreadLocalContextObject ctx) {
    threadLocal.set(ctx);
  }

  public static void unset() {
    threadLocal.remove();
  }
  public static ThreadLocalContextObject get() {
    return threadLocal.get();
  }
}

Затем из @BeforeMethod вы можете установить объект контекста, содержащий ресурс в MyThreadLocal. И из @AfterMethod вы можете удалить его из локального хранилища потока, вызвав unset.

Обратите внимание, что удаление threadlocal необходимо при сбое, что может легко привести к нехватке памяти.

threadlocal гарантирует локальное хранилище ресурса для потока, выполняющего конкретный тестовый пример.

Поэтому, отвечая на ваш вопрос, threadlocal может быть самым простым и безопасным способом сделать это, по моему мнению.

person Sumeet Sharma    schedule 24.08.2014