Ошибки, сложный материал, вопросы >
Нашли опечатку или неточность?

Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.

Что-то не получается или материал кажется сложным?

Загляните в раздел «Обсуждение»:

  • задайте вопрос нашим менторам. Вы быстрее справитесь с трудностями и прокачаете навык постановки правильных вопросов, что пригодится и в учёбе, и в работе программистом;
  • расскажите о своих впечатлениях. Если курс слишком сложный, подробный отзыв поможет нам сделать его лучше;
  • изучите вопросы других учеников и ответы на них. Это база знаний, которой можно и нужно пользоваться.
Об обучении на Хекслете

Как мы тестируем тесты

Практика курса по тестированию сильно отличается от практик других курсов. Обычно вам нужно написать реализацию какой-то функции под существующий набор тестов. Здесь же всё наоборот. Вам нужно написать тесты для готового кода.

Разберем конкретный пример. Представьте себе функцию, которая возвращает последний элемент в массиве:

const numbers = [2, 2];
console.log(last(numbers)); // 2

Можно ли однозначно утверждать, что она работает верно основываясь на примере выше? Нет. Вполне возможно, что эта функция реализована так:

const last = () => 2; // всегда возвращает 2

В таком случае понадобится еще один вызов чтобы проверить ее работу:

const numbers = [5];
console.log(last(numbers)); // 5

Достаточно ли теперь? И снова нет. Ее код может быть таким:

const last = (items) => items[0]; // возвращает первый элемент вместо последнего

При такой реализации и первый вызов и второй вернут правильные данные, хотя функция реализована неверно. А вот правильная реализация функции:

const last = (items) => items[items.length - 1];

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

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

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

// обычно это файл functions.js

// Разные реализации функции last. Имена функций не важны.
// Только одна реализация верная (right), остальные неверные (fail)
const functions = {
  right1: (items) => items[items.length - 1],
  fail1: () => 2, 
  fail2: (items) => items[0], 
};

// process.env содержит переменные окружения, среди них есть FUNCTION_VERSION, о ней ниже
// Смысл этой функции в том, чтобы вернуть нужную реализацию из списка выше
const f = (name = process.env.FUNCTION_VERSION) => functions[name] || functions['right1'];

export default f; 

Затем в файле с тестами происходит импорт этого модуля:

import getFunction from './functions.js';

// Теперь функция называется как надо
const last = getFunction();

// А тут вы пишете тесты. Как конкретно – в следующем уроке.

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

test:
	suppressor pass 'node ./tests/collection.test.js'
	FUNCTION_VERSION=fail1 suppressor fail 'node ./tests/collection.test.js'
	FUNCTION_VERSION=fail2 suppressor fail 'node ./tests/collection.test.js'

Наша проверочная система использует специальную библиотеку suppressor для запуска тестов, которая может понять, успешно ли завершилось выполнение тестов. У неё есть два режима работы:

  1. Проверяет, что тесты выполнились успешно. В такой проверке в ваши тесты подставляется правильная реализация функции, которая тестируется (без ошибок).

    # pass – проверяет что тесты успешно выполнились
    # FUNCTION_VERSION – переменная окружения, которая содержит имя функции,
    # которую надо подставить для данного запуска тестов
    FUNCTION_VERSION=right1 suppressor pass 'node ./tests/collection.test.js'
    
    # В таком случае getFunction вернет функцию (items) => items[items.length - 1]
    

    Аргумент pass говорит о том, что suppressor ожидает успешного завершения тестов. Следующий аргумент – команда, которую надо запустить. Если тесты вместо успеха завершились с ошибкой, библиотека выведет следующее сообщение:

    Expected tests to pass, but error occurred. See output above.
    

    Это значит, что для текущего запуска тестов использовалась рабочая (правильная) версия кода, для которой тесты должны завершиться успешно. Если они этого не сделали, значит тесты написаны неверно.

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

    FUNCTION_VERSION=fail1 suppressor fail 'node ./tests/collection.test.js'
    # В таком случае getFunction вернет функцию (items) => 2
    

    Аргумент fail говорит о том, что suppressor ожидает, что выполняемая команда завершится с ошибкой. Тогда тесты написаны верно. Если тесты вместо ошибки завершились успешно, библиотека выведет следующее сообщение:

    Expected tests to fail, but they passed. See output above. 
    

    Это значит, что для текущего запуска тестов использовалась неверная (нерабочая) версия кода, для которой тесты должны были упасть (сигнализировать об ошибке). Если они этого не сделали, значит тесты написаны неверно.


Дополнительные материалы

  1. Переменные окружения

<span class="translation_missing" title="translation missing: ru.web.courses.lessons.mentors.mentor_avatars">Mentor Avatars</span>

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят менторы из команды Хекслета или другие студенты.

Для полного доступа к курсу нужна профессиональная подписка

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

Получить доступ
115
курсов
892
упражнения
2241
час теории
3196
тестов

Зарегистрироваться

или войти в аккаунт

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно.

  • 115 курсов, 2000+ часов теории
  • 800 практических заданий в браузере
  • 250 000 студентов

Нажимая кнопку «Зарегистрироваться», вы даёте своё согласие на обработку персональных данных в соответствии с «Политикой конфиденциальности» и соглашаетесь с «Условиями оказания услуг». Защита от спама reCAPTCHA «Конфиденциальность» и «Условия использования».

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Rambler
Логотип компании Bookmate
Логотип компании Botmother

Есть вопрос или хотите участвовать в обсуждении?

Зарегистрируйтесь или войдите в свой аккаунт

Нажимая кнопку «Зарегистрироваться», вы даёте своё согласие на обработку персональных данных в соответствии с «Политикой конфиденциальности» и соглашаетесь с «Условиями оказания услуг». Защита от спама reCAPTCHA «Конфиденциальность» и «Условия использования».