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

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

.
Принципы SOLID для тестировщиков: принцип инверсии зависимостей
26.09.2024 00:00

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

Настало время для последнего принципа SOLID! Принцип инверсии зависимостей состоит из двух частей, и мы будем изучать их по одной. Во-первых, он гласит, что «Высокоуровневые модули должны зависеть не от низкоуровневых, а от абстракций».

Чтобы с этим разобраться, надо понять разницу между «высокоуровневыми» и «низкоуровневыми" модулями. Низкоуровневый модуль отвечает за одну конкретную задачу – например, запрос к базе данных или отправка файла на печать. Для первого примера мы используем класс AddText, очищающий текстовое поле и вводящий туда новый текст.


class AddText {
clearAndEnterText(id: string, value: string) {
driver.findElement(By.id(id)).clear().sendKeys(value)
}
}

Высокоуровневый модуль – это то, что отвечает за ключевую функциональность приложения или теста. Например, это может быть генерация отчета или создание нового пользователя. Для нашего примера мы воспользуемся классом UpdatePerson, обновляющий значение в соответствующей пользователю записи.

class UpdatePerson {
private addText: AddText
constructor(addText: AddText) {
this.addText = addText
}
update(updateId: string, updateValue: string) {
this.addText.clearAndEnterText(updateId, updateValue)
}
}

В этом примере мы обновляем запись, инициализируя класс AddText, затем инициализируя класс UpdatePerson, а затем – вызывая функцию обновления:

const addText = new AddText()
const updateUser = new UpdatePerson(addText)
updateUser.update('lastName', 'Smith')

Однако этот пример нарушает принцип инверсии зависимостей! Класс UpdatePerson очень зависим от класса AddText. Если подпись (параметры и тип возвращаемого значения) функции clearAndEnterText изменится в классе AddText, придется также менять класс UpdatePerson.

Обновим наш код, чтобы он соответствовал принципу. Вместо создания класса AddText создадим интерфейс AddText:

interface AddText {
clearAndEnterText(id: string, value, string): void
}

Затем создадим класс PersonForm, внедряющий интерфейс.

class PersonForm implements AddText {
clearAndEnterText(id: string, value: string) {
driver.findElement(By.id(id)).clear().sendKeys(value)
}
}

И, наконец, обновим класс UpdatePerson, чтобы он использовал PersonForm:

class UpdatePerson {
private form: PersonForm constructor(form: PersonForm) { this.form = form } update(updateId: string, updatevalue: string) { this.form.clearAndEnterText(updateId, updateValue) } }

Теперь мы можем обновить значение, создавая копию класса  PersonForm, а затем создавая и используя класс UpdatePerson:

const userForm = new PersonForm()
const updateUser = newUpdatePerson(userForm)
updateUser.update('lastname', 'Smith')

Теперь и класс PersonForm, и класс UpdatePerson зависят от интерфейса, а не от низкоуровневого модуля. Если подпись интерфейса clearAndEnterText изменится, нам нужно будет обновить PersonForm, но класс UpdatePerson в обновлении нуждаться не будет.

Вторая часть принципа инверсии зависимостей гласит, что «абстракции не должны зависеть от деталей: детали должны зависеть от абстракций». Абстракция – это интерфейс или абстрактный класс, который определяет набор поведений, не уточняя детали реализации. И низкоуровневые, и высокоуровневые модули должны зависеть от абстракций, и если детали внедрения меняются, они не должны влиять на абстракцию.

Иными словами, класс PersonForm может как угодно менять функцию clearAndEnterText, и это не затронет интерфейс AddText. К примеру, мы можем изменить класс PersonForm, чтобы он делал запись в лог, но на интерфейс AddText это никак не повлияет:

class PersonForm implements AddText {
clearAndEnterText(id: string, value: string) {
driver.findElement(By.id(id)).clear().sendKeys(value)
console.log('Element updated')
}
}

Итак, я завершаю мою серию из пяти статей про принципы SOLID! Отдельная благодарность моей коллеге Монике Стэндифер, которая помогла мне лучше разобраться в принципах. Я, безусловно, многому научилась, и надеюсь, что вам помогут эти простые примеры, использующие распространенные методы!

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