Разделы портала

Онлайн-тренинги

.
Принципы SOLID для тестировщиков: принцип подстановки Лисков
28.08.2024 00:00

Автор: Кристин Джеквони (Kristin Jackvony)
Оригинал статьи
Перевод: Ольга Алифанова

Мы дошли до L в SOLID! Принцип замещения Лисков назван в честь Барбары Лисков, специалистки по информатике, которая ввела эту концепцию в 1987 году. Принцип гласит, что вы должны иметь возможность заменять объекты суперкласса объектами подкласса, не изменяя программу.

Чтобы с этим разобраться, используем очень знакомый тестировщикам пример: ожидание элемента. В классе WaitForElement два метода - waitForElementToBeVisible и waitForElementToBeClickable:

class WaitForElement {
    constructor() {}
     async waitForElementToBeVisible(locator) {
         await driver
             .wait(until.elementIsVisible
             (driver.findElement(locator)),10000)
    }
    async waitForElementToBeClickable(locator) {
         await driver
              .wait(until.elementIsEnabled
               (driver.findElement(locator)),10000)
    }
}

Этот класс можно использовать для поиска любых элементов. Допустим, что тестировщик создал класс специально для клика по элементам выпадающих списков, расширяя существующий класс WaitForElement:

class WaitForDropdownSelection extends WaitForElement {
    constructor() {
         super()
    }
    async waitForElementToBeClickable(locator) {
        let selection = await driver
             .wait(until.elementIsEnabled(driver.findElement(locator)),10000)
              selection.click()
    }
}

Если мы используем класс WaitForElement для выбора города из выпадающего списка городов, это будет выглядеть так:

let waitForInstance = new WaitForElement()
waitForInstance.waitForElementToBeVisible
    (By.id(‘cities’)).click()
waitForInstance.waitForElementToBeClickable
    (By.id(‘New York’)).click()

Но если мы воспользуемся классом WaitForDropdownSelection для выбора города, это будет выглядеть вот так:

let waitForDropdownInstance = new WaitForDropdownSelection()
waitForDropdownInstance.waitForElementToBeVisible
    (By.id(‘cities’)).click()
waitForDropdownInstance.waitForElementToBeClickable
    (By.id(‘New York’))

Видите разницу? Когда мы пользуемся методом waitForElementToBeClickable в классе WaitForDropdownSelection, метод включает клик по элементу:

selection.click()

Но когда мы используем метод waitForElementToBeClickable в классе WaitForElement, то клика там нет. Это нарушает принцип замены Лисков.

Для исправления проблемы можно обновить метод waitForElementToBeClickable в WaitForDropdownSelection, чтобы там отсутствовала команда click(), а затем добавить еще один метод, который будет ждать и кликать:

class WaitForDropdownSelection extends WaitForElement {
     constructor() {
        super()
    }
    async waitForElementToBeClickable(locator) {
        await driver
            .wait(until.elementIsEnabled
            (driver.findElement(locator)), 10000)
    }
    async waitForElementAndClick(locator) {
        let selection = await driver
            .wait(until.elementIsEnabled
             (driver.findElement(locator)), 10000)
        selection.click()
    }
}

Теперь мы все исправили, и классы можно использовать взаимообразно.

При помощи класса WaitForElement:

let waitForInstance = new WaitForElement()
waitForInstance.waitForElementToBeVisible
    (By.id(‘cities’)).click()
waitForInstance.waitForElementToBeClickable
    (By.id(‘New York’)).click()

При помощи класса WaitForDropdownSelection:

let waitForDropdownInstance = new WaitForDropdownSelection()
waitForDropdownInstance.waitForElementToBeVisible
    (By.id(‘cities’)).click()
waitForDropdownInstance.waitForElementToBeClickable
    (By.id(‘New York’)).click()

Или же мы можем воспользоваться новым методом класса WaitForDropdownSelection:

let waitForDropdownInstance = new WaitForDropdownSelection()
waitForDropdownInstance.waitForElementToBeVisible
    (By.id(‘cities’)).click()
waitForDropdownInstance.waitForElementAndClick
    (By.id(‘New York’))

Использование расширенных классов – отличный способ избежать дупликации кода при добавлении новой функциональности. Однако при расширении класса убедитесь, что методы взаимозаменяемы.

Обсудить в форуме