Как найти ошибки в коде

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


Также загляните в наш Твиттер. В одном треде мы разобрали несколько примеров, когда вроде бы рабочий код не проходит тесты на Хекслете. Сам тред можно найти здесь.

Примеры в этой статье написаны на языке JavaScript, но принципы одинаковы для любого языка.

Тесты

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

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

В первую очередь нужно классифицировать проблему. Ошибки в тестах можно грубо разделить на две категории:

  • ошибки, которые выдает компилятор или интерпретатор: синтаксическая ошибка, ошибка типизации
  • ошибочные утверждения.

Утверждения

Утверждение — это специальная функция, которая вызывает ваш код с определенными параметрами и проверяет, что он возвращает ожидаемый результат. Например:

assert(isPrime(3));
assert.equal(factorial(3), 6);

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

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

assert.js:89
  throw new assert.AssertionError({
  ^
AssertionError: 3 == 1
    at Object.<anonymous> (test.js:4:8)
    at Module._compile (module.js:413:34)
    at loader (/usr/local/lib/node_modules/babel-register/lib/node.js:126:5)
    at Object.require.extensions.(anonymous function) [as .js] (/usr/local/lib/node_modules/babel-register/lib/node.js:136:7)
    at Module.load (module.js:357:32)
    at Function.Module._load (module.js:314:12)
    at Function.Module.runMain (module.js:447:10)
    at /usr/local/lib/node_modules/babel-cli/lib/_babel-node.js:161:27
    at Object.<anonymous> (/usr/local/lib/node_modules/babel-cli/lib/_babel-node.js:162:7)
    at Module._compile (module.js:413:34)

Вывод можно разделить на две части:

  • Первая — описание того, что ожидалось от функции и что было получено. В нашем примере это строка AssertionError: 3 == 1. Читается она следующим образом: «ожидалось, что функция вернет 3, но она вернула 1». Это уже хорошо, но еще хотелось бы увидеть, с какими параметрами была вызвана функция. И в этом нам поможет вторая часть вывода.
  • Вторая часть называется backtrace, она содержит список функций, которые последовательно вызывались в коде. Порядок вывода, чаще всего, обратный: в начале то, что вызывалось последним.
    В первую очередь нужно, начиная с конца, найти первое упоминание функции из файла, который похож на тестовый. Обычно его называние содержит слово test. В примере выше это at Object.<anonymous> (test.js:4:8). В скобках указана строчка, на которой находится вызов этого утверждения. В данном случае — строчка 4.
    Всё, что теперь остается, это зайти в соответствующий файл и посмотреть то, как вызывалась ваша функция.

Предупреждения компилятора и интерпретатора

Синтаксические ошибки

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

Другие ошибки

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

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

Многие из этих ошибок легко исправить с помощью отладочной печати (см. урок Отладочная печать).