How do I capture only one screenshot when I run an Automation Test on mobile also on website at the same time?

Daisy :

I have not been able to find a solution on google or on stackoverflow for my scenario and I am stuck.

For the automation testing I am using InteliJ (as IDE), java, Selenium, Appium and TestNG.

I have actions performed on the website to initialize the mobile, and after that the automation perform the actions on the mobile.

The screenshot when the test fails captures the website and the mobile screen.

I need to capture only the screen related to the failed test action.

Please see the code:

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;
}
}
Khathuluu :

With the assumption that you guys differentiate mobile actions from web actions by logging a message prefixed with "Mobile:" and that the reportLog method is always invoked within the same thread as the test method itself (e.g., testCaseOnAndroid), we can build a cache that holds the last attempted action for a given thread (test case) whenever reportLog is invoked. If a test case fails and afterTestCase is called, we can inspect the cache and get the last attempted action for the current thread (the method annotated with @AfterMethod is normally called in the same thread as the test method itself), based on which, we can now decide whether we need to call the driver that captures a screenshot of the browser window or the driver that captures a screenshot of the emulated device's screen:

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);
    }
}

A more proper solution would very likely require changing hundreds/thousands of tests (which is very likely not desired). Ideally, test case steps (actions) should be modelled more properly and not only exist in our imagination as "things" separated by reportLog method calls.

Java is an OOP language after all.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=394941&siteId=1