2016-07-27 16 views
-2

Ich habe eine gemeinsame Webdriver-Klasse erstellt, die ich für meine Selen-Tests verwenden kann. Immer wenn ich einen neuen Test erstelle, bekomme ich den Webdriver aus dieser Klasse. HierConnect Selen-Test zu SauceLabs

ist, was ich bin mit meinem Fahrer

package com.atmn.config; 

import java.net.MalformedURLException; 
import java.net.URL; 
import org.apache.commons.logging.Log; 
import org.apache.commons.logging.LogFactory; 
import org.openqa.selenium.WebDriver; 
import org.openqa.selenium.remote.CapabilityType; 
import org.openqa.selenium.remote.DesiredCapabilities; 
import org.openqa.selenium.remote.RemoteWebDriver; 

public class Driver { 


    private static Log log = LogFactory.getLog(Driver.class); 
    public static String USERNAME = "name"; 
    public static String ACCESS_KEY = "key"; 

    public static WebDriver driver = createDriver("firefox", "47.0", "Windows 10"); 

    public static WebDriver createDriver(String browser, String version, String os) { 

     try{ 
      DesiredCapabilities capabilities = new DesiredCapabilities(); 
      capabilities.setCapability(CapabilityType.BROWSER_NAME, browser); 
      capabilities.setCapability(CapabilityType.VERSION, version); 
      capabilities.setCapability(CapabilityType.PLATFORM, os); 

      // Launch remote browser and set it as the current thread 
      return new RemoteWebDriver(
        new URL("http://"+USERNAME+":"+ACCESS_KEY+"@ondemand.saucelabs.com:80/wd/hub"), 
        capabilities); 
     } 
     catch(MalformedURLException e) 
     { 
      e.printStackTrace(); 
      //log message 
      log.info(e.getMessage()); 
     } 
     return null; 
    } 

Hier zu schaffen ist mein Test, der von Windows verwenden, um auf SauceLabs läuft 10 und Firefox 47.

package com.atmn.tests; 

import com.tplus.atmn.tasks.CommonTasks; 
import com.tplus.atmn.objects.TOA6; 
import java.lang.reflect.Method; 
import org.apache.commons.logging.Log; 
import org.apache.commons.logging.LogFactory; 
import org.openqa.selenium.By; 
import org.testng.Assert; 
import org.testng.annotations.DataProvider; 
import org.testng.annotations.Test; 
import com.tplus.atmn.tasks.HttpRequest; 


public class Testing extends CommonTasks { 

    private static Log log = LogFactory.getLog(TB6_TOA.class); 


    @Test (groups = {"Testing"}) 
    public static void endToEnd() throws Exception { 


     //Load URL 
     HttpRequest http = new HttpRequest(); 
     String URL = http.internetWebAddress(); 
     driver.get(URL); 


     //Page 1 
      // Item Text 
     verifyText(Object.ItemText, "Multiple Choice - Single Answer Radio - Vertical"); 
     verifyText(Object.Progress_PercentComplete, "0%"); 
      //URL 
     verifyNoRedirect(); 
      //Go to next page 
     driver.findElement(Object.Start).click(); 
     System.out.println("Next Button was clicked."); 

} 
} 

Anstatt nur mein Lauf Test auf 1 Browser in SauceLabs, möchte ich diesen Test auf mehrere Browser/OS-Kombinationen parallel ausführen. Ich bin mir nicht sicher, wie ich meine Fahrerklasse ändern soll, um dies zu ermöglichen.

+0

Sie diese Frage google Haben? Hast du ihr Hilfe-Wiki gelesen? – JeffC

+0

Ist das eine ernste Frage? Ja, ich habe es gegoogelt. Ja, ich habe das Wiki angesehen. Ich bin nicht in der Lage, es herauszufinden, weshalb ich die Frage gestellt habe. – TestRaptor

+0

Ja, es ist eine ernste Frage. Wenn ich deine Frage googlen und Antworten in weniger als 60s finden kann, frage ich allgemein, ob der Fragesteller sich die Mühe gemacht hat, seine eigene Frage zu googeln. Hast du diesen Artikel mit dem Titel [Tests parallel ausführen] (https://wiki.saucelabs.com/display/DOCS/Java+Test+Setup+Example#JavaTestSetupExample-RunningTestsinParallel) auf dem Socelabs-Wiki gelesen? Es scheint, als würde es das haben, wonach du suchst. Wenn nicht, was fehlt? – JeffC

Antwort

0

Sie verwenden also TestNG. Dieses Testframework unterstützt das parallele Ausführen von Builds (eine Einstellung, die Sie einer Suite-Datei hinzufügen oder auf andere Weise festlegen können). Sie können auch Argumente für eine Testmethode verwenden, die DataProvider verwendet. Es gibt viele, viele Möglichkeiten, ein Test-Framework zu erstellen, und es gibt viele Faktoren, die in seine Struktur einfließen sollten.

Als Erstes erstellen Sie eine statische WebDriver-Instanz in der Driver-Klasse, die nicht das ist, was Sie wollen. Sie benötigen mehrere Instanzen. Was Sie also wirklich wollen, ist die Factory-Methode für diese Klasse, mit der Sie WebDrivers für jede Methode nach Bedarf erstellen können. Eine weitere Überlegung, die Sie berücksichtigen sollten, ist die Tatsache, dass TestNG keine neuen Instanzen des Testklassenobjekts für jede Methode erstellt. Aus diesem Grund können Sie entweder keinen Zustand als ein Feld auf dem Testklassenobjekt speichern, es sei denn, dies geschieht in einer Weise, die eine Konkurrenz vermeidet (z. B. ein Feld ThreadLocal). Leider werden Sie im Fall eines Selenium-Tests den WebDriver beenden müssen, wenn Sie damit fertig sind, um die SozeLabs-Ressourcen freizugeben. Normalerweise können Sie das mit einer Konfigurationsmethode @AfterMethod tun, aber Sie können nicht garantieren, dass die Konfigurationsmethoden im selben Thread wie die Testmethode ausgeführt werden, so dass die Verwendung eines ThreadLocal Feldes nicht den Zugriff auf das gleiche Argument ermöglicht (z. B. die Webtreiber). Sie könnten eine Karte von Testmethoden für Webtreiber auf dem Klassenobjekt verwenden (TestNG ermöglicht es Ihnen, die Testmethode als Argument zu injizieren), aber im Falle eines Datenproviders, der mehrere OS/Browser-Kombinationen zulässt, wird es den gleichen Test haben Methode auch. Am Ende mit TestNG und Selen finde ich es am besten (oder zumindest am einfachsten), nach meiner Erfahrung DataProvider zu verwenden und die Felder nur auf dem Testklassenobjekt zu speichern und die Parallelität auf Klassenebene einzuschränken.

Dies gesagt, hier ist ein Beispiel dafür, wie man mit parallelen Methoden das testen. Beginnend mit einem einfachen pom.xml Abhängigkeitsbereich, um die für dieses Beispiel verwendeten Versionen zu zeigen. Auch wenn Ihre Versionen ein wenig anders sind, sollte es sehr ähnlich sein.

<dependencies> 
    <dependency> 
     <groupId>org.seleniumhq.selenium</groupId> 
     <artifactId>selenium-java</artifactId> 
     <version>2.53.1</version> 
    </dependency> 
    <dependency> 
     <groupId>org.testng</groupId> 
     <artifactId>testng</artifactId> 
     <version>6.9.10</version> 
    </dependency> 
</dependencies> 

Aktualisieren Sie die Driver Klasse um sicherzustellen, dass es wieder sauber eine neue Treiber-Instanz jedes Mal. Ich habe die Logger-Teile entfernt, nur um Platz zu sparen. Ich habe es auch einfach nicht-instanziierbar gemacht, da es eigentlich nur eine statische Fabrik ist und Instanzen davon nicht sinnvoll erscheinen lassen. Außerdem sollten Sie wahrscheinlich keinen Zugriff auf Dinge wie den Namen und den Schlüssel erlauben, da es sich um reine Implementierungsdetails handelt.

public final class Driver { 

    private static final String USERNAME = "name"; 
    private static final String ACCESS_KEY = "key"; 

    public static WebDriver createDriver(String browser, String version, String os) { 
     // Should probably validate the arguments here 
     try { 
      DesiredCapabilities capabilities = new DesiredCapabilities(); 
      capabilities.setCapability(CapabilityType.BROWSER_NAME, browser); 
      capabilities.setCapability(CapabilityType.VERSION, version); 
      capabilities.setCapability(CapabilityType.PLATFORM, os); 
      return new RemoteWebDriver(new URL("http://" + USERNAME + ":" + ACCESS_KEY + "@ondemand.saucelabs.com:80/wd/hub"), 
             capabilities); 
     } catch (MalformedURLException e) { 
      throw new RuntimeException("Failure forming the URL to create a web driver", e); 
     } 
    } 

    private Driver() { 
     throw new AssertionError("This is a static class and shouldn't be instantiated."); 
    } 
} 

Schließlich müssen Sie in der Testklasse selbst die eigentliche Testmethode und einen Datenprovider definieren. Wenn Sie denselben Datenprovider für mehrere Tests/Testklassen benötigen, ist das in Ordnung.Wenden Sie sich an die TestNG Dokumentation:

http://testng.org/doc/documentation-main.html#parameters-dataproviders

import org.openqa.selenium.By; 
import org.openqa.selenium.WebDriver; 
import org.testng.annotations.DataProvider; 
import org.testng.annotations.Test; 

public class FooTest { 

    @DataProvider(name = "DriverInfoProvider", parallel = true) // data providers force single threaded by default 
    public Object[][] driverInfoProvider() { 
     return new Object[][] { 
      { "firefox", "47.0", "Windows 10" }, 
      { "chrome" , "51.0", "Windows 10" }, 
      // etc, etc 
     }; 
    } 

    @Test(dataProvider = "DriverInfoProvider") 
    public void testFoo(String browser, String version, String os) { 
     WebDriver driver = Driver.createDriver(browser, version, os); 
     try { 
      // simple output to see the thread for each test method instance 
      System.out.println("starting test in thread: " + Thread.currentThread().getName()); 
      // Putting this in a try catch block because you want to be sure to close the driver to free 
      // up the resources even if the test fails 
      driver.get("https://www.google.com"); 
      driver.findElement(By.name("q")).sendKeys("Hello, world"); 
     } finally { 
      driver.quit(); 
     } 
    } 
} 

Bitte beachten Sie, dass es eine Reihe von Dingen, über diese Beispiele sind, die ich nicht von einer Architektur Standpunkt mag, aber ich wollte Ihnen eine geben Vorstellung einiger der zu bedenkenden Probleme und ein schnelles Arbeitsbeispiel, das dem ähnlich ist, was Sie bereits haben. Um schließlich Testklassen parallel auszuführen, würden Sie eine TestNG-Suite erstellen und dann ausführen. Diese sind normalerweise in XML definiert (Sie können jedoch auch YAML verwenden).

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> 
<suite name="MySuiteNameHere" parallel="methods" thread-count="15"> 

    <test name="Selenium Tests"> 
     <classes> 
      <class name="foo.bar.FooTest"/> 
     </classes> 
    </test> 
</suite> 

schließlich, dass die Führung auf zwei Tests ausgeführt wird, die Google geladen und ausgeführt, um die Aktion zusammen mit dieser Beispielausgabe:

starting test in thread: PoolService-1 
starting test in thread: PoolService-0