Несколько месяцев назад я встретил единственного и неповторимого Роберта «Дядю Боба» Мартина («Чистый код», «Чистый кодер», «Чистая архитектура» и т. Д.). Один из многих вопросов, которые люди задавали ему, был: «Какие части моего приложения нужно покрыть модульными тестами?» Его ответ был: «Ну, работать только с теми, с кем хочешь работать».

Отличный ответ, правда?

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

Видение всего зеленого делает людей счастливыми, и они, как правило, оставляют его зеленым (т. Е. ., добавляя новые тесты при добавлении нового кода). Никто не хочет быть тем парнем, который сделал файл красным после того, как он долгое время оставался зеленым.

Поэтому очень важно с самого начала иметь отчеты о покрытии кода и пороговые значения. В этой статье мы настраиваем Istanbul в приложении React, используя Jest в качестве средства запуска тестов.

Давайте начнем

Начнем с приложения React. Мы будем использовать шаблон Facebook Create React App.

Create React App не требует настройки и создает очень простое приложение React с помощью одной команды:

npx create-react-app my-app-name

Теперь у вас есть приложение React. Что еще лучше: у вас есть один тест Jest в src/App.test.js.

Это все, что вам нужно для знакомства с Стамбулом. Если вам нужно больше данных, вы можете добавить еще несколько файлов и написать для них тесты или использовать существующие проекты React.

Создание Стамбула

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

Загвоздка здесь в том, что Istanbul не запускается по умолчанию, когда вы создаете свое приложение с помощью шаблона Create React App.

Есть два способа запустить Istanbul вместе с Jest при выполнении тестовых скриптов. Оба они действительно просты.

Первый запускает ваши тесты с флагом --coverage. Давайте добавим новый сценарий npm под названием test:coverage, который будет использовать Стамбул для создания отчета о покрытии после выполнения тестов:

//package.json
  {
    ...
    "scripts": {
      ...
      // test run   without coverage report      
      "test": "set CI=true && react-scripts test",
      
      // run tests in watch mode
      "test:watch": "react-scripts test",  
      // test run that generates coverage reports
      "test:coverage": "set CI=true 
                          && react-scripts test --coverage"  
    }
  }

Это лучший способ представить Стамбул в вашем приложении, потому что вы контролируете, будут ли создаваться отчеты в зависимости от того, какой скрипт вы используете.
Причина, по которой вы не хотите всегда создавать отчеты, - это производительность - создание отчетов по каждый запуск может значительно замедлить ваши тесты.
Поэтому, когда вам нужен отчет о покрытии, вы запускаете npm run test:coverage, а когда нет, вы используете npm run test, который имеет более быстрое и менее затратное выполнение.

Второй способ включить Стамбул - использовать свойство collectCoverage, которое по умолчанию имеет значение false.

//package.json
  {
    ...
    "jest": {
      collectCoverage: true
    }
  }

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

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

Настраиваемая конфигурация покрытия

В Стамбуле есть много свойств, которые позволяют настраивать отчет о покрытии. Давайте разберемся с самыми полезными или интересными.

Свойство collectCoverageFrom позволяет определить, из каких источников вы хотите и, что более важно, не хотите получать покрытие.

Вы всегда хотите исключить node_modules directory, какой-либо сторонний код, тестовые файлы и т. Д. Использование свойства collectCoverageFrom упрощает настройку. Исключение выполняется с помощью оператора отрицания: “!”.

"jest": {
    "collectCoverageFrom": [
      "**/*.{js,jsx}",
      "!**/node_modules/**",
      "!**/coverage/**",
      "!**/serviceWorker.js",
      "!**/index.js"
    ],
}

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

"jest": {
    "coverageThreshold": {
      "global": {  // global thresholds
        "branches": 80,
        "functions": 80,
        "lines": 80,
        "statements": 80
      },
      "./src/App.js": {  // file level thresholds
        "lines": 100
      }
    }
  }

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

Заключение

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

Попытки включить пороги тестового покрытия, линтеры и другие правила в конце жизненного цикла проекта почти всегда заканчиваются неудачей, которую никто не уважает.

Будьте умны и сделайте это с самого начала.