воскресенье, 26 января 2014 г.

Распараллеливание тестов WD+TestNG с использованием ThreadLocal

Распараллеливание тестов WD с использованием ThreadLocal

Итак,для тех кто не знает что такое ThreadLocal в Java

ThreadLocal — http://java.sun.com/javase/6/docs/api/java/lang/ThreadLocal.html
Незаслуженно забытый класс, существующий ещё с версии 1.2. И ставший ещё более привлекательным, подружившись с generics. Класс позволяет имея одну переменную, иметь различное значение для каждого из потоков.

То есть для тестов на WD он нам подходит идеально,чтобы не задумываться над синхронизацией между потоками и состоянии драйвера и других объектов.
Сейчас покажу то,что нам потребуется чтобы наши тесты выполнялись параллельно, каждый метод в отдельном браузере с независимым объектом WebDriver.
(каждый метод это конечно для примера,вообще на каждый метод выделять по запуску браузера-это роскошь)
Как его применить в проекте?
Примерно так:
Сделаем класс фабрику:
 
class LocalDriverFactory {
    static WebDriver createInstance(String browserName) {
        if (browserName.toLowerCase().contains("firefox")) {
            return new FirefoxDriver();
        }
        if (browserName.toLowerCase().contains("internet")) {
            return new InternetExplorerDriver();
        }
        if (browserName.toLowerCase().contains("chrome")) {
             return new ChromeDriver();
        }
        return new FirefoxDriver();
    }
}
Нам понадобится класс менеджер с ThreadLocal

 
public class LocalDriverManager {
    private static ThreadLocal webDriver = new ThreadLocal();
 
    public static WebDriver getDriver() {
        return webDriver.get();
    }
 
    static void setWebDriver(WebDriver driver) {
        webDriver.set(driver);
    }
}

Простой класс где мы сеттим в  ThreadLocal переменную WD и запрашиваем его.
Настало время переопределить TestNG Listener,для действий перед методом и после.

 
public class WebDriverListener implements IInvokedMethodListener {
 
    @Override
    public void beforeInvocation(IInvokedMethod method, ITestResult testResult) {
        if (method.isTestMethod()) {
            String browserName = method.getTestMethod().getXmlTest().getLocalParameters().get("browserName");
            WebDriver driver = LocalDriverFactory.createInstance(browserName);
            LocalDriverManager.setWebDriver(driver);
        }
    }
 
    @Override
    public void afterInvocation(IInvokedMethod method, ITestResult testResult) {
        if (method.isTestMethod()) {
            WebDriver driver = LocalDriverManager.getDriver();
            if (driver != null) {
                driver.quit();
            }
        }
    }
}
И напоследок,какой нибудь демо тест
В этом примере,у нас должны запуститься оба метода в разных потоках и с разными экземплярами WD.
Для проверки мы выводим эту информацию в консоль.

 
public class ThreadLocalDemo {
    @Test
    public void testMethod1() {
        invokeBrowser("http://www.ndtv.com");
    }
 
    @Test
    public void testMethod2() {
        invokeBrowser("http://www.facebook.com");
 
    }
 
    private void invokeBrowser(String url) {
        System.out.println("Thread id = " + Thread.currentThread().getId());
        System.out.println("Hashcode of webDriver instance = " + LocalDriverManager.getDriver().hashCode());
        LocalDriverManager.getDriver().get(url);
 
    }
}

И xml suite для запуска

 






    
        
        
            
        
     
 


 
[TestNG] Running:
Thread id = 10
Hashcode of webDriver instance = 1921042184
Thread id = 9
Hashcode of webDriver instance = 2017986718
 
===============================================
Suite
Total tests run: 2, Failures: 0, Skips: 0
===============================================

Вот и все.

5 комментариев:

  1. Сделал как описано, но тесты все равно ходят по очереди.
    Выложил https://github.com/maxslon/parallerMethods.
    Не подскажешь, что не так?

    ОтветитьУдалить
    Ответы
    1. Проблема решается, если использовать chrome.
      В FF почему-то распараллеливание не работает.

      Удалить
    2. Проверил ваш код у себя,все работает.ФФ открывается далеко не быстро,а тест у вас короткий.Один успевал завершаться,до того, как второй начинался.

      Удалить
  2. И, кстати, я правильно понимаю, что в таком виде возможен запуск только через suite xml, по одному тесту не запустить, т.к. слушатель указан в самом xml.
    Чтобы запустить отдельный тест, нужно будет указать значение атрибута @Listeners ?

    ОтветитьУдалить
    Ответы
    1. Привет,про гитхаб посмотрю позже.
      А про то что запустить можно будет только через suite.xml-нет неправильно.
      Чтобы запустить отдельный тест,нужно или у класса где находится тест,или у класса родителя выставить аннотацию,для вашего примера вот так

      @Listeners(WebDriverListener.class)
      public class ThreadLocalDemo {

      Параметр браузера только нужно в инициализации драйвера или передавать не в сьюте,или чтобы был дефолтный.
      Вот так
      static WebDriver createInstance(String browserName) {
      if (browserName.toLowerCase().contains("firefox")) {
      return new FirefoxDriver();
      }
      if (browserName.toLowerCase().contains("internet")) {
      return new InternetExplorerDriver();
      }
      if (browserName.toLowerCase().contains("chrome")) {
      return new ChromeDriver();
      }
      return new FirefoxDriver();
      }

      Удачи.

      Удалить