Селен Java: с TestNG, не выполняется 2-й контрольный пример - PullRequest
0 голосов
/ 24 апреля 2020

Вывод на консоль

Пожалуйста, помогите мне решить проблему ниже в Selenium WebDriver с Java.

Я проверяю веб-приложение eComm. У меня есть пара тестовых случаев. 1. Войдите в приложение 2. Добавьте товар в корзину. Этот тестовый пример является продолжением первого тестового примера. Это означает, что после входа пользователь собирается добавить товар в корзину.

У меня есть 2 файла классов, в которых я дал условие @Test в обоих файлах классов.

В файле класса CommonFunctions я запускаю браузер в разделе @BeforeSuite. И закрытие браузера в разделе @AfterSuite.

Я делаю это в объектной модели Page и выполняю из TestNG XML.

При запуске комплекта проходит первый тестовый пример. Когда дело доходит до второго контрольного примера (в условии @Test, присутствующего в файле 2-го класса), входящий в него раздел @Test, но безуспешный, без какой-либо причины.

Я пробовал использовать неявное, явное ожидание и даже thread.sleep. Но не повезло. Пожалуйста, можете кто-нибудь взглянуть и предложить мне.

Ценю вашу помощь!

Ответы [ 2 ]

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

Я предполагаю, что это происходит из-за какого-то исключения, и трассировка стека не печатается каким-либо образом. Попробуйте явно напечатать его:

@Test
public void SecondTestCase(){
    try{
        yourSecondTestCase;
    }
    catch(Throwable e){
        e.printStackTrace();
    }
}
0 голосов
/ 24 апреля 2020

Только не используйте драйвер повторно.

Создайте его в @BeforeMethod, затем закройте его в @AfterMethod, и у вас не возникнет никаких проблем.

Обновите ответ на вопрос с комментарием ниже:

Как правило, не рекомендуется проводить тесты в зависимости друг от друга.

Независимо от того, насколько особенным вы считаете ваше дело, вам никогда не следует делать это, если вы хочу сохранить свое достоинство.

Это не обязательно означает, что вы не можете повторно использовать 'logi c' в тестах, это просто означает, что вы не должны ожидать, что какой-либо другой тест будет выполнен до текущего .

Давайте подумаем об этом:

  1. Почему вы хотите сделать это с самого начала?
  2. Какой эффект вы ищете?

Мои скрытые ответы:

  1. Вы хотите, чтобы сначала был выполнен тест входа в систему.
  2. Это поможет вам избежать повторения того же входа код во всех оставшихся тестах, и вы экономите время от запуска / Остановка драйвера.

Если мои догадки верны, то я могу сказать вам, что совершенно нормально хотеть такие вещи, и что все, кому когда-либо требовалось написать более 2 тестов, были там

Вы можете спросить:

  1. Не пытаюсь ли я достичь того же?
  2. Где тогда моя ошибка?

Следующие ответы можно считать краткими и совершенно недостаточными по сравнению с истиной, которая скрывается за ними, но я думаю, что они послужат вам хорошим началом укажите, куда вы направляетесь.

  1. Да, вы пытаетесь достичь того же.
  2. Ваш подход нельзя назвать ошибкой, но пренебрежение - вы Вы пытаетесь написать автоматизированные тесты с Selenium, пока вам не хватает базовых навыков кодирования. Это на самом деле не так уж и плохо, потому что вы не знали, во что вы ввязываетесь, но после прочтения этого у вас есть выбор: позволить этому ускользнуть или начать путь к личному самосовершенствованию. Потратьте некоторое время на изучение Java - действительно хорошим началом будет книга «Мышление в Java». Делайте упражнения после каждой главы, и опыт, который вы получите, будет бесценным. Книга поможет вам познакомиться с возможностями языка Java и получить представление о том, как работает организация кода.

Достаточно общих замечаний, ниже приведено простое руководство, которым вы должны следовать при реализации v0.1 вашего новорожденного «проекта автоматизации» . (Да, это « проект » и « framework » имеет совершенно другое значение, чтобы быть понятным.)

Сначала вам нужно решить, как подойти к объекты страницы.

(основываясь на моем собственном опыте)

  • лучший способ сделать это - сохранить все бизнес-логи c внутри объектов страницы и с помощью business-logi c Я имею в виду:
    • все методы, которые выполняют какое-либо действие,
    • и все методы, которые получают некоторые данные.
  • Примеры включают doSomething / getSometing / setSomething / isSomething / canSomething / waitSomething и так далее.
  • Вы не должны делать никаких утверждений внутри объектов страницы
  • Вы должны никогда выбросить AssertionError из объектов вашей страницы
  • Если вам нужно что-то выбросить из метода / конструктора объекта страницы, просто
    • throw IllegalArgumentException
    • или RuntimeException.
  • Все утверждения должны произойти исключительно в теле метода-метода
  • Вы никогда не должны писать оператор assert ... вне метода @Test
  • Вы можете иметь классы Util чтобы сделать некоторые преобразования данных
    • , но никогда не записывать в них логи утверждений c
    • , а скорее предоставлять методы с логическим / другим типом возврата и утверждать их результат.

Следующий пример - один из лучших, которые я когда-либо видел:

// Don't do this:
ColorVerifications.assertAreSame(pen.getColor(), ink.getColor());

// If you do, you'll eventually end-up having to write this:
ColorVerifications.assertAreNotSame(pen.getColor(), ink.getColor());


// Do this instead:
Assert.isTrue(ColorUtil.areSame(pen.getColor(), ink.getColor());

// Then you can actually 'reuse' the logic that's already in the Assert class:
Assert.isFalse(ColorUtil.areSame(pen.getColor(), ink.getColor());

// NOTE: Regarding the term "code reuse" 
// - it is NOT referring to "reusing your own code"
// - it IS referring to "reusing all the existing code"
Идея состоит в том, чтобы четко сообщить о намерении утверждения и о том, как выполняется проверка.

Всегда держите логики c ', проверяющих ' и ', утверждающих ' отдельно, потому что эти слова имеют разные семантика .

Очень важно тщательно продумать названия классов / методов / переменных - действительно!

Не бойтесь переименовывать его, когда Вы подходите лучше - go для этого на месте!

Теперь вернемся к нашей странице, посвященной материалам и материалам для входа в систему - я не буду вдаваться в подробности, но вы получите то, что я

  • Тщательно организуйте методы @Test в отдельных классах
  • Оставьте те, которые нуждаются в общей настройке, в одном классе
  • Сохраните количество Методы тестового класса, которые не аннотированы @Test до минимума
  • Не наследуют между тестовыми классами для повторного использования logi c, кроме
    • Папки выходов / результатов preparaton / colletion / archiving
    • Журналы / Инициализация / удаление отчетов
    • Создание драйвера / cleanup
  • В общем: предпочитайте композицию наследованию
  • Поместите другие логи c в объекты объектов / утилит страницы и используйте их повторно
  • Иметь базовый класс DriverWrapper для обобщенных c проверок / взаимодействий пользовательского интерфейса
  • Иметь базовый класс PageObject, в котором размещается член DriverWrapper
  • Не использовать @FindBy / Модель PageFactory (ваша жизнь станет счастливее)
  • Используйте stati c final По локаторам вместо
  • Log all !
    • ведение журнала не включено в примеры
    • , но предполагается, что первая строка каждого метода записывает имя метода и переданные аргументы
    • всегда помните - ваш журнал - ваш лучший друг
    • Чтение того, что произошло в журнале, занимает значительно меньше времени, чем ручная отладка кода (который фактически выполняет его на половинной скорости)
    • Вы пишете код atuomation, а не рабочий код, поэтому Вы не можете ошибаться при регистрации дополнительной информации.
    • За исключением случаев паролей и конфиденциальных данных
      • тех, которые вы никогда не должны регистрировать.

Теперь, когда вы ознакомились с некоторыми базовыми c идеями, давайте погрузимся в код:

Основы страницы

Образец DriverWrapper:
class DriverWrapper {

    protected final WebDriver driver;

    public DriverWrapper(WebDriver driver){
        this.driver = Objects.requireNotNull(driver, "WebDriver was <null>!");
    }

    // it's okay to have 'checked exceptions' declared by all wait* methods
    // but it is tottaly not okay to have 'checked exceptions' for the others
    public WebElement waitForVisibleElement(By locator, int timeoutMillis) 
        throws TimeoutException { // <- the 'checked exception'
            return new WebDriverWait(driver)
                .withTimeout(Duration.ofMillis(timeoutMillis))
                .pollingEvery(Duration.ofMillis(100))
                .until(
                    ExpectedConditions.visibilityOfElementLocatedBy(locator)
                );
    }

    public boolean isVisible(By locator, int timeoutMillis){
        try{
            return waitForVisibleElement(locator, timeoutMillis) != null;
        catch(TimeoutException ignored){
            return false;
        }
    }


    // .get(String url){...}
    // .click(By locator){... elementToBeClickable(locator) ....}
    // .typeInto(bool shouldLog, By locator, CharSequence... keys){...}
    // .typeInto(By locator, CharSequence... keys){typeInto(true, locator, keys);}
    // you got the idea ;)
}
Образец PageObject:
class PageObject{

    protected final DriverWrapper driver;

    public PageObject(WebDriver driver){
        this.driver = new DriverWrappr(driver);
    }

}
Образец LoginPage:
class LoginPage extends PageObjet{

    // NOTE: keep the locators private
    private static final By USERNAME_INPUT = By.id("usernameInput");
    private static final By PASSWORD_INPUT = By.id("passwordInput");
    private static final By LOGIN_BUTTON = By.id("loginButton");
    private static final By ERROR_MESSAGE = By.id("errorMessage");

    public LoginPage(WebDriver driver){
        super(driver);
    }

    public LoginPage goTo(){ 
        driver.get(url);
        return this;
    }

    public void loginAs(String user, String pass){
        // NOTE: 
        //      Do not perform navigation (or other actions) under the hood!
        //      Resist the urge to call goTo() here!
        //      Page object methods should be transparent about what they do.
        //      This results in better level of control/transparency in the tests.

        driver.typeInto(USERNAME_INPUT, user);
        driver.typeInto(PASSWORD_INPUT, pass);
        driver.click(LOGIN_BUTTON);
    }

    public boolean isErrorMessageVisible(int timeoutMillis){
        // NOTE: We delegate the call to the driver
        //       Allowing the page-object to later define it's own isVisible method
        //       Without having collision with driver methods.

        return driver.isVisible(ERROR_MESSAGE, timeoutMillis);
    }
}

Основы инфраструктуры

Пример класса DriverManager:

class DriverManager{

    private static WebDriver driver;

    public static WebDriver getDriver(){
        return driver;
    }

    public static void setDriver(WebDriver driver){
        // NOTE: Don't do null checks here.
        DriverManager.driver = driver;
    }

    public static WebDriver createDriver(String name){
         //...
         return new ChromeDriver();
    }

Пример класса TestBase:

class TestBase{
    // NOTE: just define the methods, do not annotate them.

    public static void setUpDriver(){
        // In v0.1 we'll be sharing the driver between tests in same class
        // Assuming the tests will not be running in parallel.
        // For v1.0 you can improve the model after reading about test-listeners

        WebDriver driver = DriverManager.getDriver();
        if(driver != null){
            return;
        }

        driver = DriverManager.createDriver("chrome");
        DriverManager.setDriver(driver);
    }

    public static void tearDownDriver(){
        WebDriver driver = DriverManager.getDriver();
        if(driver != null){
            driver.quit();
            DriverManager.setDriver(null);
        }
    }
}

Наконец - тестовый класс:

class LoginTests extends TestBase{

    private LoginPage loginPage;

    @BeforeClass
    public static void setUpClass(){
        setUpDriver();
    }

    @AfterClass
    public static void tearDownClass(){
        tearDownDriver();
    }

    @BeforeMethod
    public void setUp(){
        // actions, that are common for all test cases in the class
        loginPage = new LoginPage(DriverManager.getDriver());
        loginPage.goTo();
    }

    @AfterMethod
    public void tearDown(){
        // dispose the page objets to ensure no local data leftovers
        loginPage = null;
    }

    @Test
    public void testGivenExistingCredentialsWhenLoginThenNoError(){
        loginPage.loginAs("TestUser", "plain-text password goes here");
        boolean errorHere = loginPage.isErrorMessageVisible(30 * 1000);
        Assert.assertFalse(errorHere, "Unexpected error during login!");
    }

    @Test
    public void testGivenBadCredentialsWhenLoginThenErrorShown(){
        loginPage.loginAs("bad", "guy");
        boolean errorHere = loginPage.isErrorMessageVisible(30 * 1000);
        Assert.assertTrue(errorHere, "Error message not shown!");
    }
}

Вот и все.

Надеюсь, вам понравилась поездка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...