Я ленюсь.

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

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

Для тестирования существует несколько фреймворков JavaScript. Давайте посмотрим на пример JavaScript с приведенным ниже кодом, взятым из документации Jasmine.

describe("A suite is just a function", function() {
  var a;

  it("and so is a spec", function() {
    a = true;

    expect(a).toBe(true);
  });
});

Когда вы читаете этот код, вам нужно знать вещи, которые не являются частью стандартного JavaScript.

  • Функции describe и it доступны волшебным образом.
  • describe и it получают функции, которые в какой-то момент каким-то образом будут выполнены.

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

Я не удовлетворен своими тестами.

До…

Однажды я увидел проект, тестирующий, доступно ли ключевое слово const или нет. Не помню точно, что это было. Целью было узнать, какие функции es6 доступны в браузерах. Набор тестовых файлов имел цель проверить, доступен ли const. Один из тестовых файлов в пакете, насколько я помню, доступен ниже.

const a = true

Вот и все.

Для меня describe/it были обязательными для написания тестов, но этот файл открыл мне глаза.

  • Запуск файла выкидывает - ›const недоступно
  • Запуск файла не выкидывает - ›const доступно

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

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

В качестве примера приведу файл с именем animals.js:

export const countDogs = (animals) => {
  return animals.filter(animal => animal === 'dog').length
}

Допустим, для целей нашего примера в файле animals.js есть ошибка: вместо подсчета собак мы считаем кошек:

export const countDogs = (animals) => {
  return animals.filter(animal => animal === 'cat').length
}

Мы могли бы протестировать countDogs, используя « стандартный » файл с именем animals.test.js:

import { countDogs } from './animals.js'
const actual = countDogs(['dog', 'dog', 'cat', 'cat', 'cat'])
const expected = 2
if (actual !== expected) {
  throw new Error(`countDogs should return ${expected}, got ${actual}`)
}

Чтобы выполнить этот тест в браузере, создайте html-файл и откройте его.

<!DOCTYPE html>
<html>
  <head>
    <title>countDogs test</title>
    <meta charset="utf-8" />
    <link rel="icon" href="data:," />
  </head>
<body>
  <script type="module" src="./animals.test.js"></script>
</body>
</html>

Помните ошибку, которую мы сделали в countDogs ? Поскольку мы считаем кошек вместо собак, мы получаем 3 вместо 2, и тест не проходит. См. Вывод в chrome DevTools ниже:

Если вы хотите выполнить тест с помощью Node.js, запустите файл с помощью команды node. Если вы никогда не запускали файл с использованием синтаксиса импорта с помощью Node.js, отметьте https://nodejs.org/docs/latest-v13.x/api/esm.html#esm_enhibited.

node ./animals.test.js

Некоторые преимущества начали расти:

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

Понимаете суть? Как только вы научитесь писать код на стандартном JavaScript, вы научитесь писать тесты. Вы можете начать писать более простые тесты прямо сейчас, ничего нового не узнать.

Тестовый файл - это стандартный файл

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

  • Для тестовых файлов требуется меньше переключения контекста, поскольку они являются стандартными файлами. Например, вы, вероятно, будете повторно использовать конфигурацию ESLint или повторно использовать стандартный скрипт выполнения файла для выполнения тестовых файлов.
  • Вы можете выполнять и отлаживать тестовые файлы изолированно, как если бы вы выполняли стандартный файл.
  • Ошибка, даже ошибка утверждения, не позволяет выполнить весь тестовый файл. Это означает, что вы можете знать количество неудачных тестовых файлов, а не количество неудачных утверждений. На практике мне удобнее останавливаться при первой ошибке, потому что ошибка отражает что-то неправильное. Я предпочитаю сосредотачиваться на чем-то одном и исправлять это. В противном случае вас часто засыпают утверждениями X, которые терпят неудачу только потому, что не удалось первое.
  • Тестовые файлы становится приятнее писать и читать. Это может открыть дверь для беспорядочного кода, потому что вы не находитесь под руководством среды тестирования. Но я видел много плохих тестовых файлов, потому что ограничения тестовой среды понимаются неправильно или слишком болезненно следовать. Здесь вы можете убедиться в качестве кода, как и в случае с другими файлами JavaScript (ESLint, обзор и общие рекомендации, такие как шаблон Arrange-Act-Assert).

Ограничения среды тестирования понимаются неправильно или слишком болезненно следовать.

Если вы хотите писать тесты, как предложено в этой статье, в более крупном масштабе, вам, вероятно, понадобятся две вещи:

  • Библиотека утверждений
  • Средство выполнения тестов для выполнения файлов JavaScript и сообщения о том, сколько из них не удалось (выдало ошибку).

Библиотека утверждений

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

if (actual !== expected) {
  throw new Error(`countDogs should return ${expected}, got ${actual}`)
}

Оператор сравнения отлично подходит для сравнения значений примитивов, но не приспособлен для сравнения составных значений, таких как объект или массив.

"toto" === "toto" // true
{ name: "foo" } === { name: "foo" } // false!

Вам понадобится инструмент, чтобы это сравнение было точным. Для этой работы создано множество библиотек утверждений: просто введите «библиотека утверждений» в Google, чтобы найти их. При рассмотрении библиотеки утверждений имейте в виду, что простота важна.

«equal() - мое любимое утверждение. Если бы единственное доступное утверждение в каждом наборе тестов было equal(), почти каждый набор тестов в мире был бы лучше для него ».

- Эрик Эллиот в Переосмыслении утверждения модульного теста -

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

Https://github.com/jsenv/assert

Тестовый бегун

Здесь вам нужно что-то, способное выполнять один или несколько файлов JavaScript и сообщать вам, возникла ли какая-либо ошибка. Я написал инструмент, способный запускать файлы в Chromium, Firefox, Webkit или Node.js. Он был разработан для обработки множества казней и расскажет, как это происходит.

Https://github.com/jsenv/jsenv-core

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

Заключение

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

Ваши тестовые файлы не зависят от тестовой среды. Это здорово, правда? Для меня это имеет смысл и кажется естественным.

Все готово!

Удачного кодирования или тестирования, теперь это то же самое :)