JavaScript

Тестирование наших приложений может быть утомительным и трудоемким делом. Вот почему мы пишем автоматизированные тесты: ради того, чтобы убедиться, что наш код работает, и при том самим не тратить на это непомерное количество времени. Однако как мы станем тестировать переменную, которая изменяется во время выполнения нашего кода? Например, временную метку (timestamp)? Давайте разберемся.

Приведенные далее примеры будут проиллюстрированы с использованием тестового фреймворка mocha и библиотеки утверждений chai, а также пакета mockdate. Все они свободно доступны через NPM.

Сценарий

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

function createUpdatedUser(user) {
  const date = new Date().toISOString()  return {
    ...user,
    updatedAt: date
  }
}

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

describe('#createUpdateUser', () => {
  it('returns the user with an `updatedAt` property', () => {
    const expectedData = {
      ...user,
      updatedAt: "2020-04-13T18:09:12.451Z"
    }
    
    const updatedUser = createUpdateUser(user)
    return expect(updatedUser).to.equal(expectedData)
  })
})

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

Знакомство с Mockdate

mockdate — очень полезная библиотека, которая позволяет нам создавать даты-заглушки в JavaSсript. Стоит отметить, что в ней также доступно определение типов для проектов TypeScript.

Итак, как мы настраиваем mockdate для работы в рамках нашего тестового фреймворка? Это довольно простой процесс. Во-первых, мы должны импортировать необходимые функции.

import { set, reset } from 'mockdate'

Затем мы должны установить (set) дату, которую мы хотим вернуть посредством mockdate, когда наше приложение станет запрашивать метку времени.

const date = '2020-04-13T18:09:12.451Z'
set(date) // Любой запрос к Date вернет эту дату

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

reset() // Нужно просто вызвать эту функцию

К слову, я как правило помещаю set внутрь шага beforeEach, а reset — внутрь шага afterEach, чтобы снизить потенциал для перекрестного загрязнения тест-кейсов.

Как всё это выглядит вместе?

Когда мы объединяем всю тестовую функциональность воедино, это может выглядеть примерно так. Внутри нашего теста ничего не меняется. Все, что мы делаем, — это настраиваем заглушку для нативной функциональности JavaSсript Date перед запуском теста.

import { expect } from 'chai'
import { set, reset } from 'mockdate'describe('SomeUserFile', () => {
  const user = {
    firstName: 'Basil',
    lastName: 'Fawlty'
  }
  const date = '2020-04-13T18:09:12.451Z'
  
  beforeEach(() => {
    set(date)
  })  afterEach(() => {
    reset()
  })  describe('#createUpdateUser', () => {
    it('returns the user with an `updatedAt` property', () => {
      const expectedData = {
        ...user,
        updatedAt: date
      }
    
      const updatedUser = createUpdateUser(user)
      return expect(updatedUser).to.equal(expectedData)
    })
  })
})

Теперь, если мы запустим тест, он должен пройти успешно, потому что, когда происходит вызов Date, mockdate сразу же реагирует и возвращает ожидаемую метку времени. В результате ее очень легко проверить в данных ответа.

Бонус: этот подход работает при использовании библиотек времени, таких как momentjs, которая представляет собой довольно мощный инструмент для манипулирования временем.

Вот и все!

Итак, создание дат-заглушек в JavaSсript — довольно простое дело. Ни один из существующих тестов не изменяется, поскольку вся настройка происходит вне отдельных тест-кейсов. Вы также всегда можете установить дату в конкретных тест-кейсах, если таков конкретный случай использования, но не забудьте сбросить ее, так как вы вряд ли хотите, чтобы даты-заглушки просочились в ваш следующий тест-кейс. Счастливого тестирования и удачи!

Вот несколько ссылок на ресурсы, которые могут вас заинтересовать, если вам захочется узнать больше или начать внедрять библиотеки в свои собственные наборы тестов:

MochaJS

ChaiJS

NPM mockdate

NPM mocha

NPM chai

MDN Date

Читайте также:


Перевод статьи Alex Pickering: “Mocking Dates in JavaScript Unit Tests”