Модульное тестирование

Модульное тестирование, или юнит-тестирование (англ. Unit testing) - способ тестирование программного обеспечения, при котором по-отдельности тестируются части программы (модули, классы, методы, функции и т.д.). При этом желательно, чтобы эти части были наименьшими. Таким образом модульные тесты являются базовыми тестами, над которыми идут интеграционные, приёмочные тесты, ручное тестирование.

Такие тесты обычно пишут и запускают сами программисты, посколько только программисту известно как должна работать отдельная часть программы, что ей подавать на вход, и что должно быть на выходе. После всех изменений необходимо запускать тесты, и если они не прошли, то необходимо вносить исправления в код, пока он не будет проходить тесты, если конечно тесты написаны корректно. В разработке через тестирование (TDD) модульные тесты пишутся перед написанием кода. Когда тесты выполняются успешно, код считается завершённым.

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

При написании тестов, тестируемый участок должен быть изолирован, не взаимодействовать с базой данных, файловой системой, не обращаться к другим объектам и т.п. Это позволяет уменьшить зависимость от других модулей, уменьшить связанность кода с внешним миром, сделать эти связи более абстрактными, что в свою очередь позволит легко переключаться, например, между различными СУБД. Модульные тесты, например, для класса должны проверять код только этого класса, а не в том числе и код других классов, которые в нём используются. Побочное тестирование кода других классов является ошибкой, поскольку превращает такие тесты в интеграционные. И когда такие тесты терпят неудачу, может быть неясно, где находится ошибка, в тестируемом классе или в другом классе.

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

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

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

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

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