将Selenium测试连接到SauceLabs

时间:2016-07-27 23:04:47

标签: java selenium saucelabs

我创建了一个常用的webdriver类,可以用于我的selenium测试。每当我创建一个新测试时,我都会从这个类中获取webdriver。

以下是我用来创建驱动程序的内容

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "24.0.1"

    defaultConfig {
        applicationId "com.micheal.stephen.geo"
        minSdkVersion 17
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.4.0'
}

这是我的测试,它将在SauceLabs上运行,使用Windows 10和firefox 47。

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;
    }

我不想在SauceLabs中的1个浏览器上运行我的测试,而是希望在多个浏览器/操作系统组合上并行运行此测试。我不确定如何更改我的驱动程序类以实现此目的。

1 个答案:

答案 0 :(得分:0)

所以你正在使用TestNG。该测试框架支持内置并行运行(它可以添加到套件文件中以及以其他方式设置)。它还允许您使用DataProvider接受测试方法的参数。设置测试框架的方法有很多种,而且应该考虑很多因素。

首先,您要在Driver类中创建一个静态WebDriver实例,这不是您想要的。您需要多个实例,因此您真正想要的是该类上的工厂方法,它允许您根据需要为每个方法创建WebDrivers。您要考虑的另一个考虑因素是TestNG不为每个方法创建测试类对象的新实例。因此,您可以将任何状态存储为测试类对象上的字段,除非以避免争用的方式完成(例如,例如ThreadLocal字段)。不幸的是,在Selenium测试的情况下,当你完成它以释放SauceLabs资源时,你将要退出WebDriver。您通常可以使用@AfterMethod配置方法执行此操作,但是您不能保证配置方法将在与测试方法相同的线程中运行,因此使用ThreadLocal字段赢得了'工作以允许访问相同的参数(例如Web驱动程序)。您可以使用测试方法的映射到类对象上的Web驱动程序(TestNG允许您将测试方法作为参数注入)但是在数据提供程序允许多个OS /浏览器组合的情况下,它将具有相同的测试方法也是如此。最后,根据我的经验,我发现使用DataProviders并将字段存储在测试类对象上并将并行性限制为类级别是最好的(或者至少是最简单的)。

话虽如此,这里是一个如何用并行方法测试的例子。从简单的pom.xml依赖项部分开始,以显示用于此示例的版本。即使你的版本有点不同,也应该非常相似。

<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>

更新Driver类以确保每次都干净地返回一个新的驱动程序实例。我删除了它的记录器部分只是为了节省一些空间。我也只是让它不可实例化,因为它实际上只是一个静态工厂,并允许它的实例没有意义。此外,您可能不应该允许访问名称和密钥等内容,因为它们纯粹是实现细节。

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.");
    }
}

最后,在测试类本身中,您需要定义实际的测试方法和数据提供者。如果您想为多个测试/测试类提供相同的数据提供程序,那很好。有关详细信息,请参阅TestNG文档:

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();
        }
    }
}

请注意,从架构的角度来看,这些示例有很多我不喜欢的内容,但我想让您了解一些需要考虑的问题和一个快速工作的示例这与你已经拥有的相似。最后,要并行运行测试类,您将创建并运行TestNG套件。这些通常以XML定义(尽管您也可以使用YAML)。

<!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>

最后运行导致两个测试加载谷歌并执行此操作以及此示例输出:

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