Saturday, October 25, 2008

Еще немного о пользе unit-тестирования

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

1. Unit-тесты позволяют найти баги в существующем коде

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

2. Зачастую unit-тесты позволяют быстрее и проще тестировать код, чем это можно сделать через UI

Столкнувшись с ситуацией, описанной в предыдущем примере, я начал задавать себе вопрос: почему баги не были найдены раньше, и получил достаточно простой ответ: сделать это через UI очень сложно. Наши QA, как и программисты, которые писали этот код, не виноваты – просто есть определенная степень сложности в системе, после которой и первые, и вторые просто физически не могут проверить все варианты в установленные сжатые сроки. Например, система прав учитывает с одной стороны иерархию пользователей и ролей, а с другой – иерархию объектов. Обе иерархии имеют свои правила наследования прав, которые влияют на получение окончательного результата. Вычисления очень похожи: они учитывают как иерархические связи внутри иерархии, так и связи с другими иерархиями. При этом через UI это все просто невозможно протестировать полностью в резонное время! Вот здесь-то на помощь и приходят unit-тесты. Быстро воссоздав иерархии объектов и связи между ними в тестах, мы легко нашли и обезвредили толпу багов.

3. Unit-тесты позволяют почувствовать душок, исходящий от вашего кода

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

Я не буду уже писать о том, как написанные unit-тесты помогали нам после изменения существующего кода (допустим, добавления кеширования) – здесь их польза и так ясна как день :)

No comments:

Post a Comment