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

В этой статье я расскажу о 15 вещах, для которых вы могли бы писать модульные тесты при написании модульных тестов для приложений Angular на Jasmine.

Содержание

  1. Вызываются функции тестирования
  2. Обновлены поля тестирования
  3. Результаты тестирования
  4. Тестирование получателей и установщиков
  5. Тестирование подписок и наблюдаемых
  6. Тестирование условных подписок и наблюдаемых
  7. Тестирование наблюдаемых с задержкой
  8. Тестирование навигации
  9. Режимы тестирования
  10. Тестирование локального хранилища
  11. Тестирование компонентов при отправке
  12. Тестирование детектора изменений
  13. Тестирование функций в конструкторе
  14. Тестирование детектора изменений в конструкторе
  15. Тестирование данных immutable.js

1. Вызываются функции тестирования

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

Вы также можете проверить, не вызываются ли функции, используя not.toHaveBeenCalledWith()

Присваивать результат шпиона переменной также не нужно. Вместо этого вы можете проверить шпиона

Вы также можете шпионить за частными функциями, установив тип возвращаемого значения any и получая ссылку на функцию, используя нотацию ключа объекта вместо точечной нотации, как это

2. Обновлены поля тестирования

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

Сначала мы инициализируем значение этого поля, а затем выполняем функцию и проверяем новое значение.

3. Результаты тестирования функции

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

Ваш модульный тест может выглядеть примерно так.

4. Тестирование геттеров и сеттеров

Вы также можете протестировать геттеры и сеттеры в своих компонентах. Предположим, у нас есть следующая функция получения.

Вы можете вызывать геттер в своих модульных тестах, как и любую другую функцию, но вы не добавляете круглые скобки в конце, как это

Вы также можете протестировать функции установщика. Предположим, у вас есть следующий сеттер.

Вы можете вызвать сеттеры в своем модульном тесте, присвоив ему значение.

5. Тестирование подписок и наблюдаемых объектов

Вы также можете проверить, вызываются ли правильные функции и обновляются ли правильные поля, когда наблюдаемый выводит новое значение. Предположим, что наблюдаемый объект был подписан во время инициализации компонента ngOnInit(), как показано ниже.

Нам нужно проверить, что функция handleData() вызывается и что поле data установлено.

Сначала нам нужно убедиться, что подписка создана. В этом случае подписка создается во время инициализации, которая уже должна быть сделана в блоке beforeEach() при создании компонента.

Теперь нам нужно передать новое значение, которое будет получать эта подписка. Если getData() возвращает тему, мы можем использовать эту тему для выдачи нового значения. Если он возвращает наблюдаемое, нам нужно будет отредактировать наш фиктивный apiService и создать новую тему и изменить getData() так, чтобы он возвращал наблюдаемое этого объекта, как показано ниже.

Затем в модульном тесте мы можем просто взять только что созданный объект getDataSubject и выдать новое значение. Модульный тест для проверки вызова функции handleData() может выглядеть так:

6. Тестирование условных подписок и наблюдаемых

У вас также может быть ситуация, когда у нас есть условная подписка, когда мы подписываемся на одно, если что-то верно, и подписываемся на что-то другое, если нет.

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

Чтобы написать тест для проверки того, что метод handleData() вызывается при успешной подписке, нам нужно создать новый объект в нашем модульном тесте и установить методы getThisData() и getThatData(). чтобы вернуть эту новую тему как наблюдаемую. Затем мы можем выдать новое значение из этого объекта и вызвать тест handleData().

Модульный тест может выглядеть так.

Тестирование асинхронного кода с использованием Rxjs

При тестировании асинхронного кода вам нужно обернуть свой модульный тест в fakeAsync(), а затем вызвать tick(), чтобы смоделировать течение времени и перейти к тому моменту, когда весь асинхронный код будет завершен. Затем вы можете проверить результаты. Ваш модульный тест будет выглядеть примерно так

7. Тестирование наблюдаемых с задержкой

Иногда у нас могут быть наблюдаемые, которые не сгенерированы сразу, но мы немного ждем, прежде чем сгенерировать значение. Некоторыми примерами этого являются setTimeout() и debounceTime(). С помощью setTimeout(() => {},x) мы указываем определенное время x в миллисекундах для ожидания перед выполнением некоторого кода, а с помощью debounceTime(x) мы ждем, пока значение не изменится в течение последних x миллисекунд, прежде чем передавать Значение.

Здесь мы используем debounceTime(500) для вызова функции getFirstPage() , когда пользователь ничего не вводил в поисковый запрос последние полсекунды.

Чтобы проверить это, все, что нам нужно сделать, это заменить tick() на tick(500), чтобы он подождал полсекунды в модульном тесте, прежде чем проверять, что _29 _ был вызван. Использование tick() не сработает, потому что оно сразу же проверяет, а до сих пор не было вызвано.

Вы тестируете setTimeout(() => {},x)in точно так же. Вам нужно дождаться вызова функции в модульном тесте с помощью tick(x).

8. Тестирование навигации

Чтобы проверить правильность маршрутов навигации в вашем приложении Angular, вам сначала необходимо настроить тестовую среду, чтобы использовать ту же навигационную маршрутизацию, что и в производственном приложении, что вы можете сделать на своем тестовом стенде с помощью RouterTestingModule.

Предположим, у нас есть следующие маршруты, и мы хотим проверить, можем ли мы перейти к пути / home.

В модульном тесте мы настроили canActivate()method службы аутентификации так, чтобы он возвращал значение true, чтобы пользователю было разрешено переходить по этому пути. Затем мы пробуем использовать router.navigate(), чтобы проверить, что / домой является допустимым маршрутом. Затем используйте галочку, чтобы дождаться завершения навигации. Модульный тест будет выглядеть примерно так

9. Режимы тестирования

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

В файле модульного теста для компонента, содержащего модальное окно, в блоке beforeEach() вы можете убедиться, что атрибут display CSS установлен правильно, и применить любые классы, необходимые для отображения модального окна. Затем снова вызовите detectChanges(), чтобы обновить пользовательский интерфейс. Теперь вы можете использовать querySelector() для получения модального окна из пользовательского интерфейса.

10. Тестирование локального хранилища

Вы также можете протестировать локальное хранилище в модульных тестах. На самом деле мы не проверяем, что локальное хранилище возвращает и сохраняет правильные значения, а проверяем, что вызываются сами функции.

Чтобы проверить, что функция что-то сохраняет в локальное хранилище, вы можете проверить, что функция setItem() вызывается с правильным ключом и значением.

Чтобы проверить, что функция загружает что-то из локального хранилища, вы можете проверить, что getItem()function вызывается с правильным ключом.

11. Тестирование компонентов при нажатии.

Компоненты On-Push - это те, для которых стратегия обнаружения изменений установлена ​​на OnPush. Это означает, что пользовательский интерфейс обновляется автоматически только тогда, когда полям назначаются новые ссылки, и не всегда обновляется, если значения полей изменяются.

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

В настоящее время существует давно нерешенная проблема с возможностью тестирования компонентов On-Push в Angular. Когда вы используете componentFixture.detectChanges(), он обновляет пользовательский интерфейс только при первом использовании, но не работает после этого.

Https://github.com/angular/angular/issues/12313

Это означает, что в настоящее время невозможно проверить поведение On-Push. Единственное, что мы можем сделать на данный момент, - это просто полностью отключить функцию On-Push в модульных тестах и ​​установить для стратегии обнаружения изменений значение по умолчанию в модульных тестах при настройке Test Bed. По крайней мере, таким образом вы можете продолжить другие модульные тесты, поскольку componentFixture.detectChanges() снова будет работать правильно.

12. Тестирование детектора изменений

Детектор изменений - это то, что автоматически обновляет пользовательский интерфейс при обновлении полей компонентов, но вы можете изменить его так, чтобы он обновлялся только тогда, когда вы хотите, отсоединив детектор изменений и обновив пользовательский интерфейс вручную, вызвав detectChanges(). Это помогает поддерживать отзывчивость приложения, не перезагружая данные все время после каждого небольшого изменения.

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

Но если мы отключим детектор изменений в нашем компоненте, то использование componentFixture.detectChanges() в наших модульных тестах больше не будет работать.

Вместо этого нам нужно получить ссылку на детектор изменений, используемый в нашем компоненте, и вместо этого вызвать detectChanges(), как показано ниже.

component['_cdr'].detectChanges();

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

13. Тестирование функций в конструкторе

Возможно, вы захотите протестировать функции, вызываемые во время конструктора компонента, но конструктор вызывается только один раз, как только вы создаете компонент, что обычно выполняется в beforeEach()block перед запуском ваших модульных тестов.

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

Предположим, у нас есть приведенный ниже конструктор для компонента с именем MyComponent.

Сначала мы наблюдаем за функцией getData() службы, используемой в тестах, а затем используем TestBed для создания нового компонента с использованием этой же службы.

14. Тестирование детектора изменений в конструкторе

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

Вместо этого нам нужно получить ссылку на службу детектора изменений с помощью инжектора службы компонента, а затем мы сможем следить за функциями детектора изменений. Предположим, у нас есть следующий конструктор для компонента с именем MyComponent.

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

15. Тестирование данных immutable.js

Когда вы используете библиотеку immutable.js, вы можете столкнуться с проблемами при попытке приравнять значения. Это связано с разной структурой используемых данных. Предположим, у нас есть следующий модульный тест, в котором мы пытаемся приравнять некоторые данные, используя toEqual(). Следующий тест не сработает.

Чтобы исправить это, нам нужно использовать оператор равенства is() из библиотеки immutable.js, как показано ниже.

Больше контента на plainenglish.io