为什么我的跨平台测试自动化框架不能并行运行? [英] Why won't my cross platform test automation framework run in parallel?

查看:34
本文介绍了为什么我的跨平台测试自动化框架不能并行运行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在为我公司的移动测试重写自动化测试框架.我们正在尝试使用由多个页面对象模型实现的接口,这些页面对象模型依赖于运行应用程序的移动设备的操作系统.我可以让这个框架顺序运行,甚至创建多个线程,但无论我做什么,它都不会并行运行.值得注意的是,我们使用 Appium 和一种叫做 DeviceCart/DeviceConnect 的东西,它允许我在物理上远程访问多个设备,因此这不是在网格上运行的.话虽如此,我将链接我的相关代码(这是我的同一代码的第二个版本,我编写了一个使用 ThreadLocal 的一个版本)

I am currently rewriting the automated testing framework for my company's mobile testing. We are attempting to use an interface which is implemented by multiple Page Object Models dependent on the Operating System of the mobile device the application is being run on. I can get this framework to run sequentially and even create multiple threads but it will not run in parallel no matter what I do. Of Note, we use Appium and something called the DeviceCart/DeviceConnect which allows me to physically remote into multiple devices, thus this isn't running on a grid. With that said I will link my pertinent code (this is my second version of this same code, I wrote one with and one without using ThreadLocal)

这应该为每个测试实例化一个具有新线程的新驱动程序

This should instantiate a new driver with a new thread for each Test

public class TLDriverFactory {

    private ThreadLocal < AppiumDriver < MobileElement >> tlDriver = new ThreadLocal <>();

    public synchronized void setTLDriver(OS platform, String server, String udid, String bundleID) {

        switch (platform) {
        case IOS:
            tlDriver = ThreadLocal.withInitial(() -> {
                try {
                    return new IOSDriver < MobileElement > (new URL(server), DesiredCapsManager.getDesiredCapabilities(OS.IOS, udid, bundleID));
                } catch(MalformedURLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                return null;
            });
            break;
        case ANDROID:
            tlDriver = ThreadLocal.withInitial(() -> {
                try {
                    return new AndroidDriver < MobileElement > (new URL(server), DesiredCapsManager.getDesiredCapabilities(OS.ANDROID, udid, bundleID));
                } catch(MalformedURLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                return null;
            });
            break;
        default:
            break;
        }
    }

    public synchronized ThreadLocal < AppiumDriver < MobileElement >> getTLDriver() {
        return tlDriver;
    }
}

这处理浏览器功能

public class DesiredCapsManager {

    public static DesiredCapabilities getDesiredCapabilities(OS platform, String udid, String bundleID) {
        //Set DesiredCapabilities
        DesiredCapabilities capabilities = new DesiredCapabilities();

        capabilities.setCapability("deviceConnectUserName", "User@Name.com");
        capabilities.setCapability("deviceConnectApiKey", "API-Token-Here");
        capabilities.setCapability("udid", udid);
        capabilities.setCapability("platformName", platform);
        capabilities.setCapability("bundleID", bundleID);
        //IOS only Settings
        if (platform.equals(OS.IOS)) {
            capabilities.setCapability("automationName", "XCUITest");
        }
        else {
            //Android only Settings
            capabilities.setCapability("automationName", "appium");
        }

        return capabilities;
    }
}

这是每个测试都继承的 Base Test 类

This is the Base Test class from which every test inherits

public class BaseTest {

    protected AppiumDriver < MobileElement > driver;
    protected AppiumSupport.TLDriverFactory TLDriverFactory = new AppiumSupport.TLDriverFactory();

    public enum OS {
        ANDROID,
        IOS
    }

    @AfterMethod
    public synchronized void tearDown() throws Exception {
        driver.quit();
        TLDriverFactory.getTLDriver().remove();
    }
}

这是测试用例本身

public class Test_SignIn extends BaseTest {

    protected SignInPage signInPage;

    @Parameters(value = {
        "udid",
        "bundleID",
        "platform",
        "server"
    })
    @BeforeMethod
    public void setup(String udid, String bundleID, OS platform, String server) throws MalformedURLException,
    InterruptedException {
        //Set & Get ThreadLocal Driver
        TLDriverFactory.setTLDriver(platform, server, udid, bundleID);
        driver = TLDriverFactory.getTLDriver().get();
        Thread.sleep(5000);
        switch (platform) {
        case IOS:
            signInPage = new SignInPageIOS(driver);
            break;

        case ANDROID:
            signInPage = new SignInPageAndroid(driver);
            break;

        default:
            break;
        }

        System.out.println("Current Thread ID BeforeTest: " + Thread.currentThread().getName());
    }

    @Test
    public synchronized void Authenticate() throws Exception {
        System.out.println("Current Thread ID Test 1: " + Thread.currentThread().getName());
        signInPage.Login("Username", "Password");

    }
}

这里是 testng.xml 文件

Here is the testng.xml file

   < !DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Test" parallel="tests" thread-count="4">
   <test name="SignIn" parallel ="instances" thread-count="2">
          <parameter name="udid" value="DeviceIdGoesHere" />
          <parameter name="bundleID" value="Environment.address.here" />
          <parameter name="platform" value="ANDROID" />
          <parameter name="server" value="http://deviceconnect/appium" />
          <classes>
              <class name="Test.Test_SignIn">
              </class>
          </classes>
   </test>
   <test name="SignIn2" parallel="instances" thread-count="2">
          <parameter name="udid" value="DeviceIdGoesHere" />
          <parameter name="bundleID" value="Environment.address.here" />
          <parameter name="platform" value="IOS" />
          <parameter name="server" value="http://deviceconnect/appium" />
          <classes>
              <class name="Test.Test_SignIn">
              </class>
          </classes>
   </test>
</suite>

我正在寻找的是是否有人可以确定我犯了什么错误或阻止测试并行运行的瓶颈

What I'm looking for is if anyone can determine what mistake I've made or what the bottleneck is preventing the tests from running in parallel

推荐答案

根据您目前所分享的内容,这里是应支持您的并发需求的清理和固定代码.

Based on what you have shared so far, here's the cleaned-up and fixed code that should support your concurrency requirements.

负责为每个线程创建和清理 Appium 驱动程序实例的 Driver 工厂类,如下所示:

The Driver factory class which is responsible for creation and clean-up of Appium driver instances for each and every thread, looks like below:

import io.appium.java_client.AppiumDriver;
import io.appium.java_client.MobileElement;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.ios.IOSDriver;

import java.net.MalformedURLException;
import java.net.URL;

public class TLDriverFactory {

    private static final ThreadLocal<AppiumDriver<MobileElement>> tlDriver = new ThreadLocal<>();

    public static void setTLDriver(BaseTest.OS platform, String server, String udid, String bundleID) throws MalformedURLException {

        System.out.println("Current Thread ID Driver Instantiation: " + Thread.currentThread().getName());

        AppiumDriver<MobileElement> driver;
        switch (platform) {
            case IOS:
                driver = new IOSDriver<>(new URL(server), DesiredCapsManager.getDesiredCapabilities(BaseTest.OS.IOS, udid, bundleID));
                break;

            default:
                driver = new AndroidDriver<>(new URL(server), DesiredCapsManager.getDesiredCapabilities(BaseTest.OS.ANDROID, udid, bundleID));
                break;
        }

        tlDriver.set(driver);
    }

    public static AppiumDriver<MobileElement> getTLDriver() {
        return tlDriver.get();
    }

    public static void cleanupTLDriver() {
        tlDriver.get().quit();
        tlDriver.remove();
    }
}

这是我猜测的 BaseTest 应该是所有测试的基类的样子

Here's how the BaseTest which I am guessing is supposed to be the base class for all tests, would look like

import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Parameters;

public class BaseTest {

    private static final ThreadLocal<SignInPage> signInPage = new ThreadLocal<>();

    public enum OS {
        ANDROID,
        IOS
    }

    @Parameters(value = {"udid", "bundleID", "platform", "server"})
    @BeforeMethod
    public void setup(String udid, String bundleID, OS platform, String server) throws Exception {
        //Set & Get ThreadLocal Driver
        TLDriverFactory.setTLDriver(platform, server, udid, bundleID);

        Thread.sleep(5000);
        SignInPage instance;
        switch (platform) {
            case IOS:
                instance = new SignInPageIOS(TLDriverFactory.getTLDriver());
                break;

            default:
                instance = new SignInPageAndroid(TLDriverFactory.getTLDriver());
                break;
        }

        System.out.println("Current Thread ID BeforeTest: " + Thread.currentThread().getName());
        signInPage.set(instance);
    }

    @AfterMethod
    public void tearDown() {
        System.out.println("Current Thread ID AfterTest: " + Thread.currentThread().getName());
        TLDriverFactory.cleanupTLDriver();
    }

    protected static SignInPage getPageForTest() {
        return signInPage.get();
    }

}

这是页面类的构造函数的样子

Here's how the constructor of your page classes would look like

import io.appium.java_client.AppiumDriver;
import io.appium.java_client.MobileElement;

public class SignInPageIOS extends SignInPage {
    public SignInPageIOS(AppiumDriver<MobileElement> tlDriver) {
        super(tlDriver);
    }
}

这是典型的测试用例的样子

Here's how a typical test case could look like

import org.testng.annotations.Test;

public class Test_SignIn extends BaseTest {
    @Test
    public void authenticate() {
        //Get the instance of "SignInPage" for the current thread and then work with it.
        getPageForTest().Login("Username", "Password");
    }
}

这篇关于为什么我的跨平台测试自动化框架不能并行运行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆