我正在开发 TestNG 框架,该框架与 Browserstack 集成以实现移动自动化。 该框架表现得非常好,直到我们在浏览器堆栈中运行单个线程来执行测试。 当我们集成并行执行时,问题实际上就开始了。我们的框架有一个 json 文件,我们在其中定义所有设备功能并调用它们来执行。示例如下:
"about": {
"project": "Demo-DexAutomation",
"team": "QE",
"environment": "QA",
"releaseVersion": "1.0"
},
"gui": {
"ss:remoteExecutor": {
"browserstack": {
"ss:remoteAddress": "http://hub-cloud.browserstack.com/wd/hub",
"browserstack.user": “<Username>”,
"browserstack.key": “<access key>“
}
},
"defaultProfile": "browserstack-oneplus-7T",
"multiProfile": [
"browserstack-samsung-galaxy-s21-plus",
"browserstack-oneplus-7T",
"browserstack-google-pixel-4"
],
"randomProfile": [
"browserstack-samsung-galaxy-s21-plus",
"browserstack-google-pixel-4",
"browserstack-oneplus-7T"
],
"browserstack-samsung-galaxy-s21-plus": {
"ss:remoteExecutor": "browserstack",
"platformName": "Android",
"app": "bs://fbac93a34795331e12e3949ac65d120e73422217",
"automationName": "UiAutomator2",
"device": "Samsung Galaxy S21 Plus",
"os_version": "11.0",
"project": "Android Automation",
"build": "DEX Android Smoke Execution",
"name": "Samsung Galaxy S21 Plus Tests",
"browserstack.networkLogs": true,
"autoGrantPermissions": "true",
"autoAcceptAlerts": "true",
"acceptInsecureCerts": true,
"acceptSslCert" : true
},
"browserstack-google-pixel-4": {
"ss:remoteExecutor": "browserstack",
"platformName": "Android",
"app": "bs://fbac93a34795331e12e3949ac65d120e73422217",
"automationName": "UiAutomator2",
"device": "Google Pixel 4",
"os_version": "10.0",
"project": "Android Automation",
"build": "DEX Android Smoke Execution",
"name": "Google Pixel 4 Tests",
"browserstack.networkLogs": true,
"autoGrantPermissions": "true",
"autoAcceptAlerts": "true",
"acceptInsecureCerts": true,
"acceptSslCert" : true
},
"browserstack-oneplus-7T": {
"ss:remoteExecutor": "browserstack",
"platformName": "Android",
"app": "bs://fbac93a34795331e12e3949ac65d120e73422217",
"automationName": "UiAutomator2",
"device": "OnePlus 7T",
"os_version": "10.0",
"project": "Android Automation",
"build": "DEX Android Smoke Execution",
"name": "One plus 7T Tests",
"browserstack.networkLogs": true,
"autoGrantPermissions": "true",
"autoAcceptAlerts": "true",
"acceptInsecureCerts": true,
"acceptSslCert" : true
},
}
},
"dashboard": {
"url": "http://localhost:4000",
"disabled": true
}
}
现在,我们使用上面 json 中的 RandomProfile 来运行测试用例。代码实际上会根据浏览器堆栈中设备的可用性选择随机配置文件。我们还可以使用默认配置文件和多配置文件。
随机配置文件 -> 为选择执行的每个测试用例选择不同的设备
默认配置文件 -> 调用添加到所有测试用例配置文件中的单个设备
多配置文件 -> 在配置文件下提到的每个设备中运行每个测试用例。
并行运行 TestNG 时,驱动程序退出无法正常工作。完成 @Test 注释中的每个测试用例后调用 quit 方法,会终止并行执行期间所有正在运行的会话。在 @AfterMethod 中调用 quit 时观察到相同的行为。还尝试在 @AfterTest 和 @AfterClass 中调用 driver.quit 都不起作用,最终导致在 browserstack 中给出超时会话。
几个测试用例的示例: - 我已删除下面代码片段中的 driver.quit 语句,但已按照上述方式进行了尝试。
public void likeOrUnlikeAContent() {
Profile deviceProfile = null;
try {
deviceProfile = singletonUtils.getUnusedRandomProfile(profile);
SlingshotReporter.log("********************Test Case: Like or Unlike a Content Navigating from Home Page********************");
DriverFactory.get().build(CommonUtils.setRunTimeCapability(deviceProfile, runTimeCapabilityUtils.getRuntimeCapabilities()));
mobileDriver = DriverFactory.getDriver();
CommonUtils.setSessionName(mobileDriver, "Like or Unlike a Content Navigating from Home Page");
commonUtils.loginToAppWithSSO(mobileDriver, "username1", EMPLOYEE);
HomePageFunctions homePageFunctions = new HomePageFunctions(mobileDriver);
homePageFunctions.navigateToAltimetrikTab(CommonUtils.ScrollDirection.HORIZONTAL,CommonUtils.Direction.RIGHT);
homePageFunctions.clickOnAltiverseCard();
CommonUtils.scrollIntoViewIDWithDirection(mobileDriver,CommonUtils.ScrollDirection.VERTICAL,UP,"likeContent");
Assert.assertTrue(homePageFunctions.verifyLikeButtonDisplayed());
homePageFunctions.verifyLikeCount();
CommonUtils.closeApp(mobileDriver);
CommonUtils.setStatusForTestCase(mobileDriver, "Passed", "Test Execution Completed");
singletonUtils.reAssignUsedDevices(deviceProfile.getProfileName());
} catch (Exception e) {
SlingshotReporter.log("-----------------Test case failed due to below error-----------------");
CommonUtils.setStatusForTestCase(mobileDriver, "Failed", e.getMessage());
singletonUtils.reAssignUsedDevices(Objects.requireNonNull(deviceProfile).getProfileName());
Assert.fail(e.getMessage());
}
}
@Test(groups = {"Smoke1"}, priority = 2)
public void commentAndReplyToCommentOnAContent() {
Profile deviceProfile = null;
try {
deviceProfile = singletonUtils.getUnusedRandomProfile(profile);
SlingshotReporter.log("********************Test Case: Comment and Reply to a comment on a Content Navigating from Home "
+ "Page********************");
DriverFactory.get().build(CommonUtils.setRunTimeCapability(deviceProfile, runTimeCapabilityUtils.getRuntimeCapabilities()));
mobileDriver = DriverFactory.getDriver();
CommonUtils.setSessionName(mobileDriver, "Comment and Reply to a comment on a Content Navigating from Home Page");
commonUtils.loginToAppWithSSO(mobileDriver, "username1", EMPLOYEE);
HomePageFunctions homePageFunctions = new HomePageFunctions(mobileDriver);
homePageFunctions.navigateToAltimetrikTab(CommonUtils.ScrollDirection.HORIZONTAL,CommonUtils.Direction.RIGHT);
homePageFunctions.clickOnAltiverseCard();
CommonUtils.scrollIntoViewIDWithDirection(mobileDriver,CommonUtils.ScrollDirection.VERTICAL,UP,"commentCnt");
homePageFunctions.commentOnAContent();
Assert.assertTrue(homePageFunctions.verifyCommentOrReplyPosted());
homePageFunctions.replyToAComment();
Assert.assertTrue(homePageFunctions.verifyCommentOrReplyPosted());
homePageFunctions.exitFromCommentDetailPage();
CommonUtils.closeApp(mobileDriver);
CommonUtils.setStatusForTestCase(mobileDriver, "Passed", "Test Execution Completed");
singletonUtils.reAssignUsedDevices(deviceProfile.getProfileName());
} catch (Exception e) {
SlingshotReporter.log("-----------------Test case failed due to below error-----------------");
CommonUtils.setStatusForTestCase(mobileDriver, "Failed", e.getMessage());
singletonUtils.reAssignUsedDevices(Objects.requireNonNull(deviceProfile).getProfileName());
Assert.fail(e.getMessage());
}
}
Testng Xml 看起来像这样:
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Mobile Automation" verbose="1" thread-count="3" parallel="methods">
<listeners>
<listener class-name="com.altimetrik.qe.slingshot.reporter.SlingshotTestNGReporter"/>
<listener class-name="com.altimetrik.qe.slingshot.testng.listeners.NeedsDriverListener"/>
</listeners>
<test name="DEX UI Tests">
<classes>
<class name="com.altimetrik.pp.dexapp.mobileAutomation.SmokeTests"/>
<class name="com.altimetrik.pp.dexapp.mobileAutomation.SuccessStoryTests"/>
<class name="com.altimetrik.pp.dexapp.mobileAutomation.EmployeeLandingTest"/>
<class name="com.altimetrik.pp.dexapp.mobileAutomation.InnovateAndInspireTest"/>
<class name="com.altimetrik.pp.dexapp.mobileAutomation.TweetTests"/>
<class name="com.altimetrik.pp.dexapp.mobileAutomation.ContributorTests"/>
<class name="com.altimetrik.pp.dexapp.mobileAutomation.ReviewerTests"/>
<class name="com.altimetrik.pp.dexapp.mobileAutomation.CandidateLandingTest"/>
<class name="com.altimetrik.pp.dexapp.mobileAutomation.JobOpportunitiesTests"/>
<class name="com.altimetrik.pp.dexapp.mobileAutomation.JobDetailsPageTests"/>
<class name="com.altimetrik.pp.dexapp.mobileAutomation.MySpaceTests"/>
<class name="com.altimetrik.pp.dexapp.mobileAutomation.DiscoverDexTest"/>
</classes>
</test>
</suite>
请帮助我解决这个问题,尝试了互联网上提供的所有解决方案,但没有任何效果。
使用 BeforeTest 和 AfterTest 注释与 getdriver() 方法从并行的驱动程序池中获取当前驱动程序。
AfterTest 仅包含 getdriver().quit();