当我在手机上同时在网站上运行自动化测试时,如何只捕获一张屏幕截图



我一直无法在谷歌或stackoverflow上找到适合我的场景的解决方案,我陷入了困境。

对于自动化测试,我使用InteliJ(作为IDE(、java、Selenium、Appium和TestNG。

我在网站上执行了初始化移动设备的操作,然后自动化在移动设备上执行操作。

测试失败时的屏幕截图会捕获网站和手机屏幕。

我只需要捕捉与失败的测试操作相关的屏幕。

请参阅代码:

public abstract class BaseTest implements ITest, V3RestApi, V2Api {
private boolean isMobileAppLaunched = false;
@AfterMethod
public void afterMainMethod(ITestResult result) {
try {
if (result.getStatus() == ITestResult.FAILURE) {
captureScreenshot(result);
}   
driver.quit();
if (isMobileAppLaunched) {
this.closeAppiumSession();
}
} catch (Exception e) {
e.printStackTrace();
}
}

private void captureScreenshot(ITestResult result) {
try {
String screenshotName;
File screenshot;
screenshotName = Utilities.getFileName(result.getName());
screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
this.attachScreenShotWithReport(screenshotName, screenshot, result);
if (isMobileAppLaunched) {
screenshotName = Utilities.getFileName(result.getName());
screenshot = ((TakesScreenshot) appiumDriver).getScreenshotAs(OutputType.FILE);
this.attachScreenShotWithReport(screenshotName, screenshot, result);
}
} catch (Exception e) {
logger.warn("Screenshot could not be captured for " + result.getName());
}
}
public void launchMobileApplication(MobileType mobileApplicationType) throws Exception {
this.isMobileAppLaunched = true;
}   
}
public class AndroidTestCase extends BaseTest {
@Test(description = "Test description"})
public void testCaseOnAndroid() throws Exception {
reportLog("Login into the application as User Name");
//login action to website;
reportLog("Click on Hamburger Menu");
//click action on the website;
reportLog("Activate to recognize the mobile"));
//action on site to recognize the mobile;
reportLog("Mobile: Launch Mobile Application");
//launch the mobile;
reportLog("Mobile: Login into the Mobile application as User Name");
//action to login;

reportLog("Mobile: Click on tab");
//action on Mobile;
}
}

假设你们通过记录一条前缀为"mobile:"的消息来区分移动操作和web操作,并且reportLog方法总是在与测试方法本身相同的线程内调用(例如testCaseOnAndroid(,我们可以构建一个缓存,每当调用reportLog时,它都会保存给定线程(测试用例(的最后一次尝试操作。如果测试用例失败并且调用了afterTestCase,我们可以检查缓存并获得当前线程的最后一次尝试操作(用@AfterMethod注释的方法通常在与测试方法本身相同的线程中调用(,基于此,我们现在可以决定是需要调用捕获浏览器窗口屏幕截图的驱动程序,还是捕获模拟设备屏幕截图的驱动器:

public abstract class BaseTest {
/**
* Defines the type of a reported test action.
*/
public enum ReportedActionType {
MOBILE,
WEB
}

private final ConcurrentHashMap<Long, ReportedActionType> lastAttemptedActionCache = new ConcurrentHashMap<>();
@AfterMethod
public void afterTestCase(final ITestResult testResult) {
final Long currentThreadId = currentThread().getId();
final ReportedActionType lastReportedActionType = this.lastAttemptedActionCache.get(currentThreadId);
if (testResult.getStatus() == FAILURE) {
printToConsole(String.format("Test failed while attempting to perform a '%1$s' action. | %2$s",
lastReportedActionType,
testResult.getName()));
try {
if (lastReportedActionType == MOBILE) {
captureEmulatedMobileDevice(testResult);
} else {
captureBrowserWindow(testResult);
}
} catch (final Exception exception) {
exception.printStackTrace();
}
}
// todo: quit web driver (Selenium)
// todo: quit mobile driver (close Appium session)
// irrespective of the state of the test result (success or failure), we need to make sure that we
// remove the cached information, otherwise the cache can get really
// large and this could lead to out of memory problems (we could potentially consider
// using a more sophisticated cache implementation of a 3rd-party library
// that supports time-based eviction, so that even if we forget to remove the
// cached information manually, it gets removed automatically after a fixed amount of time - e.g., 5-10 seconds)
this.lastAttemptedActionCache.remove(currentThreadId);
}
// todo: call the appropriate driver to capture a screenshot of the emulated device
private void captureEmulatedMobileDevice(final ITestResult testResult) {
printToConsole("Screenshot of the emulated mobile device has been captured. | " + testResult.getName());
}
// todo: call the appropriate driver to capture a screenshot of the browser window
private void captureBrowserWindow(final ITestResult testResult) {
printToConsole("Screenshot of the browser has been captured. | " + testResult.getName());
}
public void reportLog(final String message) {
// log the message (to console, to file, etc.)
printToConsole(message);
// the assumption is that the actions within a test case are executed within the same
// thread the test case itself is executed in; as long as this assumption holds, we can cache
// the needed information and fetch it later to perform the needed checks
this.lastAttemptedActionCache.put(currentThread().getId(),
getReportedActionType(message));
}
private ReportedActionType getReportedActionType(final String reportLogMessage) {
return reportLogMessage.toLowerCase()
.trim()
.startsWith("mobile:") ? MOBILE : WEB;
}
// todo: replace this with a proper logger
private void printToConsole(final String message) {
System.out.println(currentThread().getId() + " | " + this.getClass()
.getSimpleName() + " | " + message);
}
}

一个更合适的解决方案很可能需要更改成百上千的测试(这很可能是不希望的(。理想情况下,测试用例步骤(操作(应该更正确地建模,而不仅仅是作为reportLog方法调用分隔的"事物"存在于我们的想象中。

Java毕竟是一种面向对象的语言。

最新更新