Как мне сделать только один снимок экрана, когда я одновременно запускаю тест автоматизации на мобильном устройстве и на веб-сайте? - PullRequest
1 голос
/ 31 марта 2020

Мне не удалось найти решение в google или 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;
}
}

1 Ответ

0 голосов
/ 01 апреля 2020

Предполагается, что вы, ребята, отличаете мобильные действия от веб-действий, регистрируя сообщение с префиксом "Mobile:", и что метод 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 - это, в конце концов, OOP язык.

...