2017-08-10 1 views
0

Ich habe viele Fragen zu diesem Thema gesehen, aber keine scheint zu dem zu gehören, wonach ich suche. Ich versuche, parallel Methoden unter einer einzigen Klasse mit dem @BeforeMethod zu starten, den Browser zu starten, und @AfterMethod, um den Browser abzureißen. In diesem Beispiel wollen wir sagen, dass es sich um eine einzelne Klassendatei handelt, in der mehrere Testmethoden enthalten sind. Ich möchte 4 von ihnen gleichzeitig in verschiedenen Browsern ausführen. Wir verwenden Groovy, aber eine Java-Antwort würde ausreichen.TestNG Selen mit parallelen Gewinden

XML:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > 

<suite name="sampleSuite" thread-count="4" preserve-order="true" parallel="methods"> 
    <test name="sample"> 
     <classes> 
      <class name="tests.some.class.MyClassFile"/> 
     </classes> 
    </test> 
</suite> 

DriverFactory Klasse, die verantwortlich für einfach das Erstellen und Zurückgeben eines Browsers ist:

private static WebDriver createWebDriver() { 
    String property = System.getProperty("driver", "chrome") 
    def capabilities 

    if (property == "chrome") { 
     capabilities = DesiredCapabilities.chrome() 


    } else if (property == "firefox") { 
     System.setProperty("webdriver.gecko.driver", "/usr/local/Cellar/geckodriver/0.16.1/bin/geckodriver") 
     capabilities = DesiredCapabilities.firefox() 
    } 

    def url = System.getProperty("seleniumServerUrl", "http://localhost:4444/wd/hub") 

    if (!url) { 
     throw new IllegalStateException("No 'seleniumServerUrl' system property set") 
    } 

    def webDriver = new RemoteWebDriver(new URL(url), capabilities) 
    webDriver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS) 
    webDriver.manage().window().setSize(new Dimension(1920,1080)) 

    Runtime.addShutdownHook { 
     try { 
      webDriver.quit() 
     } catch (ignore) {} 
    } 
    webDriver 
} 

Zum Gewindeschneiden, auch in DriverFactory Klasse:

static final WebDriver createStackWebDriver(){ 
    ThreadLocal<WebDriver> webDriver = new ThreadLocal<WebDriver>(){ 
     protected WebDriver initialValue(){ 
      createWebDriver() 
     } 
    } 
    webDriver.get() 
} 

Jetzt Ich habe eine TestPlatform-Klasse, die das zentrale "Aufbau- und Abbau-Stück" der Architektur ist. Alle meine Klassendateien, die die @Test Methoden enthalten erweitert diese TestPlatform Klasse:

class TestPlatform { 

    WebDriver webDriver 

    @BeforeMethod 
    void startUpWebBrowser(){ 
     webDriver = DriverFactory.createStackWebDriver() 
    } 

    @AfterMethod 
    void quitWebDriver(){ 
     webDriver.quit() 
    } 
} 

Wenn wir die XML-Datei ausführen, was wir 4 Fälle von startUpWebBrowser() sehen, der 4 würde „pass“ ein und auch weiterhin die Test, und es wird sofort 4 Methoden aus einer Instanz von startUpWebBrowser() öffnen, während die anderen 3 einfach "hängen" bleiben. Wir benötigen es, um einen Browser in jeder Instanz zu öffnen, anstatt 4 Browser in einer Instanz.

Unsere aktuelle Problemumgehung ist EACH @Test Methode innerhalb der eigenen Klasse wickeln, und die @BeforeMethod in @BeforeClass sowie den after ändern. Das funktioniert irgendwie, ist aber auf der Berichtsseite sehr hässlich, und es gibt andere wenige Nachteile auf diese Weise.

Gibt es eine Lösung für dieses Problem ohne eine Überarbeitung der aktuellen Architektur? Fehle ich gerade etwas sehr einfaches?

+0

Die Webdriver-Variable in der TestPlatform ist nicht threadsicher. Wäre es nicht einfacher, die ThreadLocal-Variable als statische final in die TestPlatform-Klasse zu verschieben und die DriverFactory.createWebDriver() in der initialValue-Methode aufzurufen. Keine Notwendigkeit für die Vorher-Methode, da Sie den threadspezifischen Treiber mit get() für die threadlokale Variable in den Testmethoden erhalten können. Außerdem haben Sie einen Shutdown-Hook für die Treiber-Quit-Methode und auch einen Quit-Aufruf im Aftermethod. Das Aftermethod kann auch entfernt werden. – Grasshopper

Antwort

1

Das Problem liegt in Ihrer Testklasse TestPlatform, in der Sie eine Webdriver-Instanzvariable in einem Datenelement auf Klassenebene WebDriver webDriver speichern.

Also, wenn zwei oder mehr @Test Methoden parallel ausgeführt werden, versuchen alle buchstäblich, die Webdriver-Instanz derselben Instanz webDriver zuzuweisen.

Bitte beheben Sie es wie folgt.

class TestPlatform { 

    @BeforeMethod 
    void startUpWebBrowser(){ 
     DriverFactory.createStackWebDriver() 
     //Access webdriver instances only via DriverFactory.createStackWebDriver() 
    } 

    @AfterMethod 
    void quitWebDriver(){ 
     DriverFactory.createStackWebDriver().quit() 
    } 
} 
1

Scheint wie ein ThreadLocal Missbrauch. Ich würde verwenden Sie den folgenden Code-Schnipsel:

private static final ThreadLocal<WebDriver> DRIVER_CONTAINER = new ThreadLocal<>(); 

@BeforeMethod 
void startUpWebBrowser(){ 
    DRIVER_CONTAINER.set(createWebDriver()); 
} 

@AfterMethod 
void quitWebDriver(){ 
    ofNullable(getDriver()).ifPresent(WebDriver::quit); 
    DRIVER_CONTAINER.remove(); 
} 

public static WebDriver getDriver() { 
    return DRIVER_CONTAINER.get(); 
} 

Oder nur Treiber-Management-Stück in IInvokedMethodListener bewegen.

Verwandte Themen