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

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

.
Улучшаем тест-автоматизацию при помощи значимой документации кода
25.03.2024 00:00

Автор: Яник Диксон (Yanique Dickson)
Оригинал статьи
Перевод: Ольга Алифанова

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

И новички, и даже те, кто имеет опыт работы с уже существующим проектом тест-автоматизации, могут растеряться, разглядывая чужой код. Иногда вы возвращаетесь и к своему собственному, давно написанному коду, и думаете: «Черт его знает, что тут происходит». Распространенные причины замешательства:

  • Имена методов, функций и классов не следуют внятному соглашению о наименованиях, и не особенно информативно передают их цели.
  • Документация скудная или отсутствует – ни строк документации (docstring), ни комментариев, определяющих функции и классы.

Значение осмысленной документации базы кода

В большинстве проектов вы сотрудничаете с другими тест-инженерами. Хорошая документация сильно упростит это сотрудничество. В этой статье вы увидите, как комментарии, строки документации и соглашение о наименованиях в коде упростят поддержку вашего проекта автоматизации, а также его понимание вами и другими членами команды. Ответственно документируя код, вы сделаете процесс его использования коллегами менее болезненным. Ваши коллеги (и менеджеры) оценят эти усилия по достоинству.

Примеры будут на JavaScript. Не волнуйтесь: эти подсказки применимы к любому языку программирования, главное – пользоваться правильным синтаксисом документации, переходя с языка на язык.

Осмысленные комментарии кода

Комментарии – это аннотации в базе кода. Они имеют форму текстовых строк, а в JavaScript начинаются с двух прямых слэшей, //. Это простой и эффективный способ добавить в код контекст. Как правило, их добавляют, чтобы объяснить, как код работает, и с какой целью он был написан.

Два простых правила для комментариев

Комментарии нужны, чтобы проинформировать читателя при помощи кратких фраз или предложений, повышающих читабельность исходного кода. Размышляя над комментариями, решите сначала, нужны ли они в принципе. Можно воспользоваться правилами ниже.

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

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

// login.cy.js
describe('Should test the sign in function', () => {
    it('should sign in successfully', () => {
        // Переход на сайт
        cy.visit('the-testwebsite.com')
        // Ввод имени пользователя
        cy.get('#username').type('user09876')
        // Ввод пароля, нажатие Enter
        cy.get('#password').type('testpassword{enter}')
        // Проверка, что мы перешли на страницу Inventory
        cy.url().should('include', '/inventory.html')
    });
});
  1. Будьте информативными и четкими. Если суть очень сложна, и ее легко неправильно понять, добавляйте в код комментарий, объясняющий его предназначение. В целом комментарии обязательны, если вы добавляете в проект свои собственные классы и функции.

Зачастую в тест-автоматизации встречаются ситуации, когда более сложные строки кода спрятаны с глаз и становятся частью классов в файлах Page Object и других вспомогательных файлов. Пример такого кода – ниже в функции getRandomState. Эта функция должна выполнять некие действия с данными, применяемыми в тест-наборе. Автор функции добавил комментарий, описывающий, что она делает, а также объясняющий читателю, что для ее работы импортированы данные.

// dataHandler.js
const listOfStates = require("../data/states");
export class DataHandler {
    // Возвращает случайное состояние из списка состояний
    // Примечание: listOfStates – это список, импортированный в начале файла
    getRandomState() {
        const numberOfStates = listOfStates.length
        const randomStateIndex
            = Math.floor(Math.random() * numberOfStates) + 1;
        const state = listOfStates[randomStateIndex]
        return state
    };
};

Сила строк документации

Еще один полезный способ документирования кода – это добавление строк документации. Они похожи на комментарии и ассоциируются с определенным блоком кода, объясняя пользователю, что это за объект и как им пользоваться.

Строки документации очень полезны, потому что сильно улучшают возможность повторного использования кода. При их наличии можно ознакомиться с определениями добавленных классов и функций. В текстовых редакторах вроде Visual Studio Code можно навести курсор на объекты и увидеть содержание строк документации – так ими пользоваться еще проще.

 

Строки документации особенно полезны, если в разработке вашего проекта автоматизации используется модель Page Object или другие вспомогательные файлы. Ожидается, что вы и ваши коллеги будете вновь и вновь пользоваться объектами из этих файлов, и строки документации упрощают это. Они объясняют, что делает объект, тем, кто захочет им воспользоваться. Функции и классы из этих файлов – отличные кандидаты для строк документации.

В JavaScript строки документации добавляются над объявлением объекта. В других языках вроде Python это, как правило, первая конструкция в блоке кода после объявления объекта.

Первая строка в строках документации – это, как правило, краткое описание того, что делает объект. Последующие строки перечисляют типы информации, ассоциированные с объектом. Часто документируемые типы информации – это:

  • Аргументы функций – тег @param. Тип данных каждого аргумента указывается в скобках – {}.
  • Примеры использования функций – тег @example. Людям, желающим использовать ваш код, полезно видеть примеры точного применения функции.
  • Возвращаемое значение – тег @returns. Это не всегда часть блока кода, но описание возвращаемого значения – дело хорошее.

Пример ниже – это класс SignupPage с кратким описанием того, что он делает. Меж тем у метода signUp есть свое собственное описание с параметрами и примером использования.

// signupPage.js
/**
* Stores methods and page elements for the Sign-up page.
*/
export class SignupPage {
    /**
    * Fills out the Sign Up form and submits it. 
    * @param {*} username the user's username
    * @param {string} password the user's  password
    * @param {number} age the user's age
    * @example signUp('testuser', 'testPassword', 19)
    */
    signUp(username, password, age) {
        cy.get('#user-name').type(username)
        cy.get('#password').type(password)
       cy.get('#user-age').type(age)
       cy.get('#signup-button').click()
    };
};

Разработка и следование хорошим соглашениям о наименованиях

Соглашение о наименованиях – это набор стандартов именования переменных, функций, классов, файлов, директорий, и т. д. Эти стандарты, конечно, не высечены в камне, но широко применяются большей частью разработчиков.

Соглашения о наименованиях стоит использовать – они упрощают организацию данных в проекте и делают их логичнее, что, в свою очередь, упрощает понимание вашего кода. Договоренность о таком стандарте делает проекты более связными.

Типы соглашений о наименованиях

Четыре самых популярных соглашения:

  • Camel Case, где первая бука – строчная. Если в имени несколько слов, все последующие слова должны начинаться с прописной буквы без пробелов между словами. Пример: переменная firstName, функция getRandomState, файл userData.js.
  • Snake Case – все буквы в словах строчные, а слова разделены знаком подчеркивания (_). К примеру, first_name, get_random_state, user_data.js.
  • Kebab Case похож на Snake Case – все буквы строчные, но вместо знака подчеркивания используется дефис (-). Примеры: first-name, get-random-state, user-data.js.
  • Pascal Case, в котором все слова в имени начинаются с прописной буквы. Как и в Camel Case, между словами нет пробелов. Пример: FirstName, GetRandomState, UserData.js.

В соглашении о наименованиях важно использовать говорящие имена и избегать аббревиатур и акронимов, известных только в узких кругах или сложных для запоминания. Эта стратегия помогает проинформировать читателя, что это за объект, и повышает читабельность исходного кода. К примеру, если ваша переменная – это почасовая ставка сотрудника, и вы называете ее ehr, читатель может это неправильно понять. Однако имя вроде employeeHourlyRate в точности описывает, что это за переменная.

Такой же подход нужно применять, давая имена файлам. Если ваш файл Page Object относится к странице приложения «Моя информация», то имя вроде myInformationPage.js даст читателю достаточно информации.

Создавая имена, в начале обычно добавляют префикс с существительным или глаголом, в зависимости от типа элемента. Имена функций и методов должны начинаться с глагола – это совершаемые действия. К примеру, метод, получающий случайное состояние из списка состояний, может предваряться глаголом get и называться getRandomState.

Другие элементы, например, классы, переменные и имена файлов, представляющие собой некие данные или сущности, начинаются с существительного. К примеру, файл с тестами для валидных кейсов авторизации пользователя можно назвать validUserLogin.spec.js, а переменную с валидным паролем пользователя, используемым в кейсе – validPassword. Имена, начинающиеся с глаголов, тоже могут быть полезными, особенно если переменная содержит элементы, выполняющие действия. К примеру, переменная, хранящая такой элемент страницы, как отправляющая email кнопка, может называться sendEmailButton. В этом случае имя имеет префикс с глаголом send, но все еще соответствует соглашению, так как описывает относящийся к нему элемент.

Выбор соглашения о наименованиях

Решая, каким соглашением пользоваться, лучше всего выбирать соглашения, которые уже широко применяются в языке программирования вашего исходного кода. Также можно обсудить с командой, какие стандарты будут использоваться, и следить за последовательностью их применения, как только вы остановились на соглашении. В JavaScript, к примеру, для имен переменных и файлов обычно используется Camel Case. Однако если дело касается классов, используется Pascal Case.

Заключение

Цель эффективных стратегий документации кода – дать информацию, повышающую читабельность и возможность повторного использования вашего кода. Спросите себя, поняли бы вы код, если бы не вы его писали? Если ответ близок к «нет», обязательно добавьте комментарии (но только там, где это необходимо), а также строки документации для методов и классов.

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

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