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

Такой подход к процессу разработки программного обеспечения имеет свои преимущества:

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

В этом блоге вы получите общее представление о том, что такое Jest, зачем его использовать и как использовать Jest для модульного тестирования.

Надеюсь, вам понравится остальная часть блога. 😄

Что и почему шутить

Jest — это средство запуска тестов JavaScript, то есть библиотека JavaScript для создания, запуска и структурирования тестов. Jest поставляется в виде пакета NPM, вы можете установить его в любой проект JavaScript.

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

Настройка проекта с шуткой

  • Создайте папку с помощью mkdir learning_jest && cd learning_jest
  • Настройка среды NPM npm init -y
  • Установите Jest, используя npm i jest --save-dev

После этого мы внесем изменения в файл package.json, чтобы мы могли запустить наш тестовый файл.

[package.json]
"script": {
    "test": "jest --verbose"
}

Использование --verbose покажет подробности о каждом тестовом примере. (Попробуйте ту же команду без этого флага, чтобы увидеть разницу)

Определение желаемого результата

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

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

const user = {
    username: "John Doe",
    tweets:[ 
      { 
        likes: 100,
        content: "Tweet 1 content..."
      },
      {
        likes: 100,
        content: "Tweet 2 content..."
      }
    ]
  }

Мы будем писать 2 функции,

  • getTotalLikes чтобы получить общее количество лайков твитов пользователя
  • getMostPopularTweet для возврата объекта твита указанного пользователя с наибольшим количеством лайков

Следуя процессу TDD, мы разработаем тесты для этих функций до разработки логики самих функций.

У нас есть намерение для функции, давайте инициализируем наш тестовый файл.

Инициализируйте тестовые файлы

Для хранения всех наших тестовых файлов у нас может быть папка tests или __test__. Вы также можете хранить тестовые файлы в любом месте каталога проекта, но рекомендуется собрать все тестовые файлы в одном месте.

Имя файла должно иметь .test.js, а фактическое имя должно совпадать с именем файла, в котором вы собираетесь писать свою функцию.

mkdir __test__ && cd __test__ && touch demoFunction.test.js

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

// example.test.js file
{ getTotalLikes, getMostPopularTweet } = require("../exampleFunction.js")

// user object using which we are going to test these 2 functions
const user = {
    username: "John Doe",
    tweets:[ 
      { 
        likes: 200,
        content: "Tweet 1 content..."
      },
      {
        likes: 90,
        content: "Tweet 2 content..."
      }
    ]
  }

Теперь приготовьтесь написать свой первый тестовый пример. ✨

Написание тестов

Тесты обычно содержат следующие общие компоненты:

  • функция describe — принимает 2 аргумента.

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

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

  • функция test — принимает 2 аргумента

строка — описывает действие для конкретного теста

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

expect Функция принимает тестируемый вызов и связана с matcher функцией, которая описывает ожидаемые результаты.

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

Добавив тест для функции, наш файл будет выглядеть так:

// example.test.js file
{ getTotalLikes, getMostPopularTweet } = require("../exampleFunction.js")

// user object using which we are going to test these 2 functions
const user = {
    username: "John Doe",
    tweets:[ 
      { 
        likes: 200,
        content: "Tweet 1 content..."
      },
      {
        likes: 90,
        content: "Tweet 2 content..."
      }
    ]
  }

describe("getTotalLikes", ()=>{
    test("should return the total likes of a user", ()=>{
       expect(getTotalLikes(user)).toBe(290)
    })
})

Здесь сопоставитель .toBe используется для сопоставления ожидаемого вывода с фактическим возвращаемым значением функции.

Фреймворк Jest предоставляет множество сопоставителей для работы.

  • toBeNull соответствует только нулю
  • toBeUndefined соответствует только undefined
  • toBeTruthy соответствует всему, что оператор if считает истинным
  • toBeFalsy соответствует всему, что оператор if считает ложным
  • toBeGreaterThan или toBeLessThan для сравнения числовых значений
  • toMatch принимает шаблон Regex для соответствия строковому выводу
  • toContain можно использовать, чтобы увидеть, содержится ли значение в массиве

Чтобы увидеть полный список совпадений, посетите этот официальный документ.

Для нашей второй функции, getMostPopularTweet, мы определим ожидаемый объект вывода в блоке describe и передадим этот объект в функцию сопоставления. Для этого мы будем использовать сопоставитель toEqual, который обычно используется для работы с массивами и объектами.

describe('getMostPopularTweet', () => {
  test('should return the most popular tweet of a user', () => {
    const output = {
        likes: 200,
        content: "Tweet 1 Content..."
    }
    expect( getMostPopularBlog(user)).toEqual(output)
  })
})

Давайте попробуем запустить наш тестовый файл, используя npm test

Ой! наши тесты провалились!

Потому что мы не определили функции для тестирования.

Давайте решим это и напишем реальные функции.

Функции записи

Создайте файл с именем exampleFunction.js, который будет содержать наши функции. Имя файла должно совпадать с именем тестового файла.

// exampleFunction.js file
function getTotalLikes( user ){
  // iterate through the tweet entries and sum the like values
  const totalLikes = user.tweets.reduce( (total, tweet) => {
    return total += tweet.likes
  }, 0)

  return totalLikes;
}

function getMostPopularTweet( user ){
  const maxLikes = user.tweets.reduce( (max, tweet, index) => {
      if (tweet.likes > max.likes) {
        return {
          index: index, 
          likes: tweet.likes
        }
      } else {
        return max
      }
  }, {index: undefined, likes: 0} )
  const topTweet = user.tweets[ maxLikes.index ]
  return topTweet
}

module.exports = { getTotalLikes, getMostPopularTweet }

Теперь, когда у нас все готово, давайте запустим наши тесты.

Запуск тестов

Используйте следующую команду для запуска всех тестовых файлов:

npm test

Вас встретят индикаторы прохождения тестов.

Заключение

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

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

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

Продолжайте тестировать ❤️

Библиография

Официальный документ Jest

Сопоставители шуток

Шутка кроме

Урок шутки

GitHub Jest Demo