Класс B1 написан и протестирован. Теперь надо реализовать и протестировать класс А, который использует IB. Стоит ли создавать BTest, реализующий IB, или же можно воспользоваться готовым B1?
Аргументы за использование B1:
— IB имеет достаточно сложную семантику, которую придется реализовывать в BTest (и отлаживать)
— В рабочем коде A и B1 будут использоваться вместе, возможно при этом проявятся дополнительные ошибки в B1 (не выявленные тестами B1). При использовании B1 для тестов мы имеем еще и интеграционное тестирование A + B1
Аргументы за использование BTest:
— Какие-то особенности A проще протестировать, имея контроль над реализацией IB
Правильно наверное сделать отдельно тесты A+BTest, а затем интеграционные A+B1. Но это сильное дублирование кода, да и просто нет времени так делать.
Это классическая ситуация, когда надо использовать мок -- только не вручную, конечно, его изготавливать, а воспользоваться одним из многочисленных фреймворков.
Здравствуйте, enji, Вы писали:
E>Привет!
E>Есть такая система: E>
E>Класс B1 написан и протестирован. Теперь надо реализовать и протестировать класс А, который использует IB. Стоит ли создавать BTest, реализующий IB, или же можно воспользоваться готовым B1?
E>Аргументы за использование B1: E> — IB имеет достаточно сложную семантику, которую придется реализовывать в BTest (и отлаживать) E> — В рабочем коде A и B1 будут использоваться вместе, возможно при этом проявятся дополнительные ошибки в B1 (не выявленные тестами B1). При использовании B1 для тестов мы имеем еще и интеграционное тестирование A + B1
E>Аргументы за использование BTest: E> — Какие-то особенности A проще протестировать, имея контроль над реализацией IB
E>Правильно наверное сделать отдельно тесты A+BTest, а затем интеграционные A+B1. Но это сильное дублирование кода, да и просто нет времени так делать.
E>А вы как считаете?
Здравствуйте, ulu, Вы писали:
ulu>Это классическая ситуация, когда надо использовать мок -- только не вручную, конечно, его изготавливать, а воспользоваться одним из многочисленных фреймворков.
IB имеет мало методов, не проблема реализовать их руками. Проблема в том, что многие методы IB получают ссылки на А и дергают их по определенному протоколу. Если использовать мок, то придется делать ограниченную поддержку этого протокола или в самом моке или в тестовом коде.
Тогда оба варианта сильно запудрят ситуацию. Если Вы склонны прислушиваться к тестам, я бы изменил реализацию взаимодействия классов.
Здравствуйте, enji, Вы писали:
E>Здравствуйте, ulu, Вы писали:
ulu>>Это классическая ситуация, когда надо использовать мок -- только не вручную, конечно, его изготавливать, а воспользоваться одним из многочисленных фреймворков.
E>IB имеет мало методов, не проблема реализовать их руками. Проблема в том, что многие методы IB получают ссылки на А и дергают их по определенному протоколу. Если использовать мок, то придется делать ограниченную поддержку этого протокола или в самом моке или в тестовом коде.
Здравствуйте, enji, Вы писали:
E>А вы как считаете?
Можно еще использовать прием с overriding (как это на русском?). То есть сделать своего наследника от B — BTest1 и перекрыть методы, которые имеют нежелательную привязку к среде или к другим классам, которые нам не нужны.
Зависит от того, на сколько сложный класс B, и какое подмножество методов надо тестировать.
E> — IB имеет достаточно сложную семантику, которую придется реализовывать в BTest (и отлаживать)
Как уже сказали, тут самое время прислушаться к тестам. Трудно тестировать = плохая архитектура.
E> Проблема в том, что многие методы IB получают ссылки на А и дергают их по определенному протоколу.
Т.е. имеем циклическую зависимость, да еще и на класс. Прямая дорога в ад partial mocks Лучше всего ликвидировать ее вообще.
Для начала выделите из A интерфейс, которым пользуется B и назовите его в терминах роли, которую A играет для B, что-то типа BWorkListener.
А вообще каждый класс должен иметь изолированные unit-тесты (т.е. единственным реальным классом в тестах должен быть только он сам + internals, т.е. private классы, которые рассматриваются как детали внутренней реализации и своих тестов не имеют). Такие тесты должны покрывать все варианты использования класса. Если не получается (например, число возможных комбинаций параметров метода или количество комбинаций последовательности вызовов зависимых методов (и такое бывает) превышает разумные пределы), то это явный признак слишком большого класса.
Интеграционных же тестов должно быть намного, намного меньше и не стоит в них пытаться проверить все и вся — это невозможно просто потому, что количество таких тестов будет равно количеству всех возможных комбинаций unit-тестов отдельных классов. Интеграционные тесты должны проверять, что кластер классов действительно может работать как единое целое, не более.
Здравствуйте, -VaS-, Вы писали:
VS>А вообще каждый класс должен иметь изолированные unit-тесты (т.е. единственным реальным классом в тестах должен быть только он сам + internals, т.е. private классы, которые рассматриваются как детали внутренней реализации и своих тестов не имеют). Такие тесты должны покрывать все варианты использования класса. Если не получается (например, число возможных комбинаций параметров метода или количество комбинаций последовательности вызовов зависимых методов (и такое бывает) превышает разумные пределы), то это явный признак слишком большого класса.
Одни догмы.
VS>Интеграционных же тестов должно быть намного, намного меньше и не стоит в них пытаться проверить все и вся — это невозможно просто потому, что количество таких тестов будет равно количеству всех возможных комбинаций unit-тестов отдельных классов.
С чего бы это? Зачем тестировать все возможные комбинации связей классов, когда достаточно протестировать только те, которые будут работать в реальном продукте? Для этого тестировщиками разрабатываются тест кейзы на основе юзкейзов, далее эти тесткейзы автоматизируются. Таких тесткейзов не много, на порядок меньше, чем юнит тестов, так как один функциональный тесткейз легко может покрывать сотню-другую юнит тестов.
VS>Интеграционные тесты должны проверять, что кластер классов действительно может работать как единое целое, не более.
Очень спорно. Я вообще не вижу смысла в проверки каких-то абстрактных ситуаций, которые программист себе понапридумывал во время разработки юнит тестов, когда можно проверить то, с чем реально столкнется пользователь. Другое дело, что не все умеют писать функциональные автотесты. Но это уже другая проблема.
ИМХО, юнит тесты — это компромисс, когда надо либо обеспечить высокую скорость их выполнения, либо когда по каким-либо причинам нет возможности создать или сэмулировать продуктовое рабочее окружение, либо когда надо протестировать библиотеку (то есть юнит тесты выполняют роль конечного пользователя). Но при наличии выбора: функциональный автотест или юниттест, то функциональный автотест по всем остальным параметрам выигрывает у юниттеста.