Было много причин, по которым я воздерживался от добавления автоматического тестирования в свои приложения в прошлом. Одним из них было незнание соотношения выгод и затрат. Другая мысль заключается в том, что их будет сложно интегрировать в существующие производственные приложения. Как нам протестировать наши приложения, не переписывая их с нуля только для того, чтобы ввести в них тестирование?

Давайте начнем с краткого определения типов тестов. Существует много типов тестов приложений, но два наиболее распространенных — это модульные тесты и сквозные тесты (также известные как интеграционные тесты). Модульное тестирование — это тип тестирования, который проверяет поведение самого вашего кода. Это не имеет ничего общего с тем, что видит пользователь, но гарантирует, что ваши методы делают то, для чего они предназначены. Интеграционное тестирование — это тип тестирования, который имитирует то, что пользователь намеревался сделать с приложениями. Так, например, он автоматизирует процесс входа в систему, создания сообщений, выхода из системы. Все это происходит автоматически, и вы можете увидеть, как это происходит визуально.

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

Модульные тесты по-прежнему важны, но я считаю, что если вам нужно было начать с одного, сквозное тестирование — лучший выбор. В этой статье мы будем тестировать существующее приложение Angular 2 todo. Мы будем использовать интеграционные тесты и рассмотрим несколько сценариев.

Если вам нужно ознакомиться с тем, как начать работу с Angular 2, взгляните на эту другую Статья об Angular 2 от Jscrambler.

Сценарии для тестирования

  • Когда приложение первоначально загружается, у нас должно быть три задачи в списке.
  • Мы должны иметь возможность добавить новую задачу.
  • Мы должны иметь возможность нажать на задачу и перейти на страницу сведений об этой задаче.
  • Мы должны иметь возможность удалить todo.
  • Мы должны иметь возможность редактировать заголовок задачи и видеть, как новый заголовок отражается на главной странице в списке задач после сохранения задачи.
  • Нам не должно быть разрешено сохранять пустую задачу, и список задач должен оставаться той же длины после нажатия отключенной кнопки сохранения.
  • Изначально кнопка добавления новой задачи должна быть отключена, когда мы загружаем домашнюю страницу.
  • Кнопка «Сохранить задачу» должна быть включена только тогда, когда мы начинаем вводить название задачи.

Схема приложения Todo

Давайте кратко опишем наше приложение todo. Сначала приложение выведет список todos на главной странице. Три, если быть точным. Данные не будут поступать с сервера, а будут загружаться из жестко заданного файла фикстуры.

На главной странице мы можем добавить новые todos. Мы также можем посетить страницу сведений todo, нажав на ее название. На этой странице мы можем отредактировать заголовок todo или удалить todo.

Клонировать и настроить приложение Todo

  • Клонировать непроверенное приложение, которое я запушил в репозиторий здесь

Убедитесь, что вы находитесь на главной ветке. Затем вам нужно установить несколько инструментов, чтобы иметь возможность следовать. На момент написания этого руководства Angular 2 вышел из Release Candidate и находится в версии 2.

  • Убедитесь, что у вас установлена ​​версия NodeJS Node 4.x.x или выше.
  • Установите зависимости узла с помощью команды

npm install

находясь внутри клонированного репозитория

  • Разработка ведется с помощью Angular-CLI.

Установите Angular-CLI глобально, используя

npm install -g angular-cli@latest

  • Сквозные тесты Angular 2 запускаются с использованием инструмента под названием транспортир.

Установите транспортир глобально, используя

npm install -g protractor

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

ng serve

и перейдите по URL-адресу браузера http://localhost:4200, где вы увидите три списка todos.

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

Важные концепции тестирования Angular 2

Сквозные тесты находятся в папке e2e. Там уже есть образец тестового файла с именем es2/app.e2e-spec.ts.

Тесты там написаны на фреймворке jasmine. Существует много способов модульности и организации сквозных тестов Angular 2, но для простоты мы поместим все тесты для этой статьи в один файл.

Наше приложение имеет только одну задачу — todos. Ради любопытства и для тех, кто хочет чего-то более сложного, чем приведенное выше, давайте представим сценарий, в котором это было бы более сложное приложение, которое имеет другие проблемы, такие как orders, userProfile. Я бы обработал тесты для этого приложения, создав папку внутри e2e для каждой из этих проблем и поместив соответствующие тесты в каждую папку.

В этом случае у нас будет две папки с именами e2e/orders и e2e/userProfile. У нас может быть только один тестовый файл в каждой папке или несколько, чтобы удовлетворить подразделы каждой из этих проблем, если нам это нужно. Единственное, о чем следует помнить, это то, что каждый из файлов должен заканчиваться словом e2e-spec.ts, чтобы программа запуска теста транспортира могла подобрать тестовые файлы.

Итак, вернемся к нашему простому тесту с одним файлом. Если вы заглянете в файл, то увидите оператор импорта вверху. В этот импорт мы помещаем общие функции, которые будут использоваться несколькими тестами. Однако в этой статье мы не будем его использовать. Думайте об этом как о библиотеке функций.

После оператора импорта у нас есть блок describe, в котором есть вызовы двух других функций, а именно beforeEach и it внутри обратного вызова.

Обратный вызов, переданный beforeEach, вызывается для каждого теста внутри блока описания. Оставьте все как есть.

Отдельные тесты помещаются внутрь обратного вызова, передаваемого функции it.

Запустим текущий тест с помощью команды

protractor

Если у вас возникли проблемы с запуском транспортира, запустите любую из этих двух команд, как указано здесь.

./node_modules/protractor/bin/webdriver-manager update

or

webdriver-manager update

Текущий тест должен завершиться неудачно, так как он ожидает увидеть текст "приложение работает" на главной странице. Это не так, поскольку мы изменили содержимое домашней страницы.

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

ПЕРЕХОД ПО СТРАНИЦАМ

Внутри тестовых файлов доступна глобальная переменная с именем browser. Он импортируется с помощью оператора импорта

import { browser, element, by } from 'protractor/globals';

которые вы можете добавить туда сейчас.

Мы используем это для перехода на любую страницу, доступную в нашем приложении, например, написав

browser.get('/');

перейти на главную страницу и

browser.get('/users');

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

ВЫБОР ЭЛЕМЕНТОВ

Обычной практикой является выделение элементов на текущей странице. Существует глобальная переменная с именем element, которую вы можете использовать для выбора элементов. Он принимает локатор, который может быть создан с использованием глобального имени by.

Пример выбора тега p с классом зеленый выполняется с помощью

let greenParagraph = element(by.css('p.green'));

Чтобы выбрать много элементов, вы должны использовать небольшое изменение

let greenParagraphs = element.all(by.css('p.green'));

Это даст массив, а не один элемент.

ЗАХВАТЫВАНИЕ ЭЛЕМЕНТА ТЕКСТА

Чтобы получить текст элемента, вы должны сначала выбрать его, как указано выше, а затем вызвать функцию getText для результата следующим образом.

let greenParagraph = element(by.css('p.green'));
let text = greenParagraph.getText();

НАЖИМАНИЕ ЭЛЕМЕНТОВ

Нажатие элементов может быть выполнено с использованием приведенного ниже синтаксиса.

let submitButton = element(by("form .submit-button"));
submitButton.click();

СЧЕТ ЭЛЕМЕНТОВ

Мы также можем подсчитывать элементы, используя приведенный ниже синтаксис.

let blueParagraphsList = elements.all(by("p.blue"));
let count = blueParagraphsList.count();

Сценарии испытаний

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

ПОДТВЕРДИТЕ, ЧТО У НАС ЕСТЬ ТРИ ЗАДАЧИ ИЗНАЧАЛЬНО

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

Внутри тестового файла e2e/app.e2e-spec.ts удалите вызов функции it под блоком beforeEach и добавьте туда

it("should show three todos when we first load the todo app", () => {
  browser.get("/");
  let todos = element.all(by.css(".todos .todo"));
  expect(todos.count()).toEqual(3);
})

Не забудьте добавить этот оператор импорта вверху этого файла.

import { browser, element, by } from 'protractor/globals';

Теперь, когда вы запускаете команду protractor, окна другого браузера будут быстро открываться и закрываться, а в вашей консоли вы должны увидеть пройденный тест зеленым цветом.

Ура! Мы только что написали наш первый сквозной тест Angular 2.

ДОБАВИТЬ НОВОЕ ЗАДАЧУ

Теперь на следующий. Мы должны иметь возможность добавить новую задачу. Давайте добавим еще один тестовый блок it, используя следующий код.

it("should be able to add a new todo", () => {
  browser.get("/");
  let newTodoInput = element(by.css(".add-todo input[type=text]"));
  newTodoInput.sendKeys("Todo 4");
  let newTodoSubmitButton = element(by.css(".add-todo input[type=submit]"));
  newTodoSubmitButton.click();
  let todos = element.all(by.css(".todos .todo"));
  expect(todos.count()).toEqual(4);
})

Здесь мы ввели текст в новое поле ввода todo, а затем отправили форму. Затем мы проверили, есть ли у нас теперь четыре todos. Если это так, то наш тест пройден.

Мы только что представили еще одну функцию под названием sendKeys. Это можно вызвать для выбранного элемента. Он используется для ввода текста в такие элементы, как поля ввода.

ПОСМОТРЕТЬ СТРАНИЦУ ДЕТАЛИ

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

it("should be able to click on a todo on the homepage and get to the details page", () => {
  browser.get("/");
  let firstTodo = element.all(by.css(".todos .todo")).first();
  let firstTodoText = firstTodo.getText();
  firstTodo.click();
  let inputFieldText = element(by.css("todo input[type=text]")).getAttribute("value");
  expect(inputFieldText).toEqual(firstTodoText);
})

УДАЛИТЬ ЗАДАЧУ

У нас должна быть возможность удалить todo. Теперь давайте попробуем удалить todo и посмотрим, получилось ли у нас.

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

it("should be able to delete a todo", () => {
  browser.get("/");
  let firstTodo = element.all(by.css(".todos .todo")).first();
  firstTodo.click();
  let deleteLink = element(by.cssContainingText("span", "Delete"));
  deleteLink.click();
  let todosList = element.all(by.css(".todos .todo"));
  expect(todosList.count()).toEqual(2);
})

ИЗМЕНИТЬ НАЗВАНИЕ ЗАДАЧИ

Мы должны иметь возможность редактировать заголовок todo и видеть, как новый заголовок отражается на главной странице в списке todos после сохранения todo.

it("should be able to edit a todo title", () => {
  browser.get("/");
  let firstTodo = element.all(by.css(".todos .todo")).first();
  firstTodo.click();
  let todoInputField = element(by.css("todo input[type=text]"));
  todoInputField.clear();
  todoInputField.sendKeys("Editted Todo1 Title");
  let saveButton = element(by.css("todo button[type=submit]"));
  saveButton.click();
  firstTodo = element.all(by.css(".todos .todo")).first();
  let firstTodoText = firstTodo.getText();
  expect(firstTodoText).toEqual("Editted Todo1 Title");
})

НЕ МОЖЕТ СОХРАНИТЬ ПУСТОЙ ЗАДАЧА

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

it("should not be able to save an empty todo", () => {
  browser.get("/");
  let newTodoInput = element(by.css(".add-todo input[type=text]"));
  let newTodoSubmitButton = element(by.css(".add-todo input[type=submit]"));
  newTodoSubmitButton.click();
  let todos = element.all(by.css(".todos .todo"));
  expect(todos.count()).toEqual(3);
})

КНОПКА СОХРАНИТЬ ИЗНАЧАЛЬНО ОТКЛЮЧЕНА

Изначально кнопка добавления новой todo должна быть отключена, поэтому добавьте эти строки кода

it("should have add todo button be disabled initially", () => {
  browser.get("/");
  let newTodoSubmitButton = element(by.css(".add-todo input[type=submit]"));
  expect(newTodoSubmitButton.isEnabled()).toEqual(false);
})

ВКЛЮЧИТЕ КНОПКУ СОХРАНИТЬ, КОГДА МЫ НАЧНЕМ ВВОД

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

it("should only enable save todo button when we start typing a new todo title", () => {
  browser.get("/");
  let newTodoSubmitButton = element(by.css(".add-todo input[type=submit]"));
  let newTodoInputField = element(by.css(".add-todo input[type=text]"));
  newTodoInputField.sendKeys("New Todo 4");
  expect(newTodoSubmitButton.isEnabled()).toEqual(true);
})

Вывод

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

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

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

Первоначально опубликовано на сайте blog.jscrambler.com 13 октября 2016 г.