我正在使用 TestNG 和 Cucumber 运行并行测试。我正在使用 ThreadLocal 管理驱动程序对象。但是,我注意到 setDriver 和 getDriver 方法在不同的线程 ID 上运行,这导致 getDriver() 返回 null。问题似乎是并行测试中不同线程之间的不兼容。在调试期间,setDriver 和 getDriver 在不同的线程 ID 上运行。当我禁用并行操作时,测试工作正常。不过ThreadLocal在并行模式下好像不兼容。
package utilities;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.options.UiAutomator2Options;
import java.net.URL;
import java.time.Duration;
public class DriverManager {
private static ThreadLocal<AndroidDriver> driver = new ThreadLocal<>();
public static void setDriver (String deviceName,String platformName,String platformVersion,String port) {
if (driver.get() == null) {
try {
System.out.println("setDriver - Thread ID: " + Thread.currentThread().getId());
UiAutomator2Options options = new UiAutomator2Options();
options.setPlatformName(platformName);
options.setPlatformVersion(platformVersion);
options.setDeviceName(deviceName);
options.setAppPackage(ConfigReader.getProperty("appPackage"));
options.setAppActivity(ConfigReader.getProperty("appActivity"));
options.setAutomationName("UiAutomator2");
options.setNewCommandTimeout(Duration.ofSeconds(3600));
options.setAutoGrantPermissions(true);
options.setApp(ConfigReader.getProperty("app"));
options.setFullReset(true);
String appiumServerURL = ConfigReader.getProperty("appiumServerURL");
//String url="http://"+ConfigReader.getProperty("ip")+":"+port+"/wd/hub";
AndroidDriver driverInstance = new AndroidDriver(new URL(appiumServerURL), options);
driverInstance.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
driver.set(driverInstance);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Driver başlatılamadı: " + e.getMessage());
}
}
}
public static AndroidDriver getDriver() {
System.out.println("getDriver - Thread ID: " + Thread.currentThread().getId());
return driver.get();
}
public static void quitDriver() {
if (driver.get() != null) {
driver.get().quit();
driver.remove();
}
}
}
package utilities;
import io.cucumber.testng.AbstractTestNGCucumberTests;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Parameters;
public class TestBase extends AbstractTestNGCucumberTests {
@BeforeTest
@Parameters({"deviceName","platformName","platformVersion","port"})
public void beforeMethod(String deviceName,String platformName,String platformVersion,String port){
try {
System.out.println("TestNG: @BeforeTest çalıştı.");
DriverManager.setDriver(deviceName,platformName,platformVersion,port);
}catch (Exception e){
e.printStackTrace();
}
}
}
package runners;
import io.cucumber.testng.AbstractTestNGCucumberTests;
import io.cucumber.testng.CucumberOptions;
import org.testng.annotations.DataProvider;
import utilities.TestBase;
@CucumberOptions(
features = "src/test/resources/features",
glue = {"steps","utilities"},
plugin = {"pretty","html:target/cucumber-reports-testng.html"},
monochrome = true,
dryRun = false,
tags = "@hepsiburada1"
)
public class TestNGRunner extends TestBase {
@Override
@DataProvider(parallel = true)
public Object[][] scenarios() { return super.scenarios(); }
}
package runners;
import io.cucumber.testng.AbstractTestNGCucumberTests;
import io.cucumber.testng.CucumberOptions;
import org.testng.annotations.DataProvider;
import utilities.TestBase;
@CucumberOptions(
features = "src/test/resources/features",
glue = {"steps","utilities"},
plugin = {"pretty","html:target/cucumber-reports-testng.html"},
monochrome = true,
dryRun = false,
tags = "@hepsiburada2"
)
public class TestNGRunner2 extends TestBase {
@Override
@DataProvider(parallel = true)
public Object[][] scenarios() { return super.scenarios(); }
}
另外,Parameters注释看不到我在testng.xml文件中给出的参数
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Cucumber Test Suite" parallel="tests" thread-count="2">
<test name="Cucumber Tests">
<parameter name="deviceName" value="emulator-5554"></parameter>
<parameter name="platformName" value="Android"></parameter>
<parameter name="platformVersion" value="14.0"></parameter>
<parameter name="port" value="4723"></parameter>
<classes>
<class name="runners.TestNGRunner" />
</classes>
</test>
<test name="Cucumber Tests 2">
<parameter name="deviceName" value="emulator-5556"></parameter>
<parameter name="platformName" value="Android"></parameter>
<parameter name="platformVersion" value="14.0"></parameter>
<parameter name="port" value="4725"></parameter>
<classes>
<class name="runners.TestNGRunner" />
</classes>
</test>
</suite>
这在某种程度上是预料之中的。
@BeforeTest
方法在所有场景之前运行一次。当场景并行运行时,它们将是一个不同的线程。
而是内联
AbstractTestNGCucumberTests
并将 Web 驱动程序的配置存储在运行程序类中。然后,在每个场景执行之前,在 runScenario
方法中,根据关闭的运行程序中存储的配置创建 Web 驱动程序。