I have a framework of mobile test automation and i made many changes to allow my code to support parallel execution but i encounter a problem which is the following: When the first thread terminates, his tearDown stop the other running thread, for infomation i have two appium server and driver instances that are running.
Cucumber runner is:
package com.runners;
import io.cucumber.testng.*;
import org.apache.logging.log4j.ThreadContext;
import org.testng.annotations.*;
import tabesto.testing.drivers.DriverManagerMobile.AndroidDeviceA;
import tabesto.testing.drivers.DriverManagerMobile.AppiumServer;
import tabesto.testing.integration.reporter.GlobalParams;
import java.io.File;
import java.time.Duration;
public class RunnerBase {
private static final ThreadLocal<TestNGCucumberRunner> testNGCucumberRunner = new ThreadLocal<>();
public static TestNGCucumberRunner getRunner(){
return testNGCucumberRunner.get();
}
private static void setRunner(TestNGCucumberRunner testNGCucumberRunner1){
testNGCucumberRunner.set(testNGCucumberRunner1);
}
@Parameters({"platformName", "udid", "deviceName", "systemPort",
"chromeDriverPort"})
@BeforeClass(alwaysRun = true)
public void setUpClass(String platformName, String udid, String deviceName, @Optional("Android") String systemPort,
@Optional("Android") String chromeDriverPort) throws Exception {
GlobalParams params = new GlobalParams();
String strFile = "logs" + File.separator + "Android";
File logFile = new File(strFile);
if (!logFile.exists()) {
logFile.mkdirs();
}
ThreadContext.put("ROUTINGKEY", strFile);
params.setPlatformName(platformName);
params.setUDID(udid);
params.setDeviceName(deviceName);
params.setSystemPort(systemPort);
params.setChromeDriverPort(chromeDriverPort);
new AppiumServer().startServer();
new AndroidDeviceA().initializeDriver();
AndroidDeviceA.getDriver().manage().timeouts().implicitlyWait(Duration.ofSeconds(4));
setRunner(new TestNGCucumberRunner(this.getClass()));
}
@Test(groups = "cucumber", description = "Runs Cucumber Scenarios", dataProvider = "scenarios")
public void scenario(PickleWrapper pickle, FeatureWrapper cucumberFeature) throws Throwable {
getRunner().runScenario(pickle.getPickle());
}
@DataProvider
public Object[][] scenarios() {
return getRunner().provideScenarios();
}
@AfterClass(alwaysRun = true)
public void tearDownClass(){
AndroidDeviceA driverManager = new AndroidDeviceA();
if(driverManager.getDriver() != null){
driverManager.getDriver().quit();
driverManager.setDriver(null);
}
AppiumServer serverManager = new AppiumServer();
if(serverManager.getServer() != null){
serverManager.getServer().stop();
}
if(testNGCucumberRunner != null){
getRunner().finish();
}
}
}
AndroidDriver code:
package tabesto.testing.drivers.DriverManagerMobile;
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.android.AndroidDriver;
import tabesto.testing.config.Settings;
import tabesto.testing.utils.HelpersMethod;
import java.io.IOException;
public class AndroidDeviceA {
private static final ThreadLocal<AndroidDriver> driver = new ThreadLocal<>();
HelpersMethod utils = new HelpersMethod();
public static AndroidDriver getDriver() {
return driver.get();
}
public static void setDriver(AndroidDriver driver2) {
driver.set(driver2);
}
public void initializeDriver() throws Exception {
AndroidDriver driver = null;
try {
utils.log().info("initializing Appium driver");
if (Boolean.getBoolean(Settings.getInstance().getModeDebug())){
new AppiumServer();
driver = new AndroidDriver(AppiumServer.getServer().getUrl(), new UiAutomatorOptions().getUiAutomatorOptionsMobile());
}else
{
driver = new AndroidDriver(new UiAutomatorOptions().getUiAutomatorOptionsMobile());
}
if (driver == null) {
throw new Exception("driver is null. ABORT!!!");
}
utils.log().info("Driver is initialized");
AndroidDeviceA.setDriver(driver);
} catch (IOException e) {
e.printStackTrace();
utils.log().fatal("Driver initialization failure. ABORT !!!!" + e.toString());
throw e;
}
}
}
Appium Server code:
package tabesto.testing.drivers.DriverManagerMobile;
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.service.local.AppiumDriverLocalService;
import io.appium.java_client.service.local.AppiumServerHasNotBeenStartedLocallyException;
import io.appium.java_client.service.local.AppiumServiceBuilder;
import io.appium.java_client.service.local.flags.GeneralServerFlag;
import tabesto.testing.integration.reporter.GlobalParams;
import tabesto.testing.utils.HelpersMethod;
import java.io.File;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.util.Date;
public class AppiumServer {
private static final ThreadLocal<AppiumDriverLocalService> server = new ThreadLocal<>();
HelpersMethod utils = new HelpersMethod();
public static AppiumDriverLocalService getServer(){
return server.get();
}
public static void setServer(AppiumDriverLocalService server2) {
server.set(server2);
}
public void startServer(){
AppiumDriverLocalService server = WindowsGetAppiumService();
server.start();
if(server == null || !server.isRunning()){
utils.log().fatal("Appium server not started. ABORT!!!");
throw new AppiumServerHasNotBeenStartedLocallyException("Appium server not started. ABORT!!!");
}
AppiumServer.setServer(server);
utils.log().info("Appium server started");
}
private String getDateTime() {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
Date date = new Date();
return dateFormat.format(date);
}
public AppiumDriverLocalService WindowsGetAppiumService() {
GlobalParams params = new GlobalParams();
return AppiumDriverLocalService.buildService(new AppiumServiceBuilder()
.usingAnyFreePort()
.withArgument(GeneralServerFlag.SESSION_OVERRIDE)
.withTimeout(Duration.ofSeconds(120))
.withLogFile(new File(params.getPlatformName() + "_"
+ params.getDeviceName() + File.separator + getDateTime()+".log")));
}
}
TestnG XML:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Suite" parallel="tests">
<listeners>
<listener class-name="test.testing.integration.reporter.InfluxDBListener" />
</listeners>
<test name="GalaxyTabA">
<parameter name="platformName" value="Android" />
<parameter name="udid" value="R52N102P7GJ" />
<parameter name="deviceName" value="Galaxy Tab A" />
<parameter name="systemPort" value="10000" />
<parameter name="chromeDriverPort" value="11000" />
<classes>
<class name="com.runners.MyPixel2XLTestNGRunnerTest"/>
</classes>
</test>
<test name="GalaxyTab">
<parameter name="platformName" value="Android" />
<parameter name="udid" value="R9WM91REZCJ" />
<parameter name="deviceName" value="Galaxy Tab" />
<parameter name="systemPort" value="10002" />
<parameter name="chromeDriverPort" value="11002" />
<classes>
<class name="com.runners.MyPixel4XLTestNGRunnerTest"/>
</classes>
</test>
</suite>
Run parallel test and i expected that if one thread is teardown, the other thread must continue to run.
Thanks in advance.