Рекомендации по написанию тестов с применением моков 
Сегодня прочитал интересную статью The Virtues of Mockery: A mock is like a stub with attitude. В ней Noel Rappin приводит несколько рекомендаций, которые он использует в процессе написания тестов с применением моков.
В моем вольном переводе они выглядят так:
1. Все внешнее окружение тестируемого метода должно быть представлено моками;
2. Внесение одной ошибки в тестируемый код не должно приводить к провалу более чем одного теста;
3. Используйте созданные моки для информирования о структуре программы.
Попытаюсь немного осмыслить полученную информацию. Больше всего вопросов вызывает вторая рекомендация, которая по сути призывает изолировать каждый метод в отдельном тесте с собственным окружением.
Допустим, у нас есть класс, в котором есть несколько методов, способных изменить состояние объекта. Если методы независимы от текущего состояния объекта, то можно проверить их по отдельности в двух разных тестах. Тогда внесение ошибки в один метод будет приводить к провалу только одного теста.
Более интересно рассмотреть ситуацию, когда методы зависят от текущего состояния объекта. Тогда, нарушение в работе одного метода может привести к тому что объект будет находится в некотором неопределенном состоянии, и это в свою очередь приведет к ошибкам в работе других функций. Как следствие провалятся сразу несколько тестов.
Самый простой выход из этой ситуации заключается в том, чтобы включать все зависимые функции в один тест. Но что если от одной функции зависят несколько методов, которые в свою очередь не могут или не должны использоваться вместе?
Например, есть класс phpbb_poster, который отвечает за публикацию постов в phpbb форум. У него есть публичные методы login, publish_post, get_categories, logout. Получается, что все функции завязаны на login, поэтому ошибка в этой функции приведет к провалу всех тестов этого класса. Самое простое и самое неправильное решение - включить все методы в один тест. Но тогда тест получится раздутым и малопонятным, а этого хотелось бы избежать. Тем более, проблема здесь явно в неправильной архитектуре класса Phpbb_poster.
В приведенном примере проблема легко решается путем вынесения функции login в отдельный класс Phpbb_session с методами login, logout. Объект этого класса является источником данных для функций класса Phpbb_poster. В результате замены Phpbb_sedsion на мок (первая рекомендация) методы publish_post и get_categories могут быть протестированны отдельно.
Возникает вопрос, всегда ли зависимость от какой-то одной функции является проблемой архитектуры? Мне кажется, что да. Я пытался придумать другие примеры, где для успешного тестирования требуется объединить все методы в один тест, но во всех случаях приходил к выводу, что проблему можно решить с помощью инверсии зависимостей.
подписаться на блог
Leave a Reply