Комментарии 24
1) Статья некая обзорная лекция о тестировании применимая думаю на любой платформе и любом языке.
Зачем в заглавии слово Android?
2) Скорее вопрос. Я согласен с определениием юнит тестов.
Но скажите пожалуйста у Вас в фирме при написании тестов действительно «Чаще всего в качестве юнита выбирается какой-либо класс».
Думаю, что это скорее исключениие. Реально выбирается модуль состоящий обычно из множества классов.
Ну для примера можно скачать с GitHab нескольно приложений в который есть тесты.
Специально я не исследовал, но на вскидку не нашел ни одного в котором тестировался бы каждый класс отдельно.
Почему я на это обратил внимание?
В фирме где я работаю начитались таких утверждений и считают это образцом.
Ну а так как классов у нас тысячи (порядка 5 000) и в каждом классе минимум пять функций,
то написание Юнит тестов это хотя и надо, но непозволительно долго.
3) Утверждение что Написание тестов значительно увеличивает время разработки справедливо в первую очередь если UnitTest пишется на объекты низкого уровня.
Если разработчик не парится по поводу размера юнита, а пишет тесты исходя из здравого смысла, то возможно даже и сокращает.
Юнит тесты тестируют именно поведение классов. Модули, состоящие из множества классов тестируют интеграционными тестами.
Классический подход прост. Сначала пишем тест, потом пишем код, поведение которого проверяется в тесте. Ну а поведенческий код в объектно-ориентированной парадигме обычно упаковывается в класс. Поэтому юнит тесты обычно тестируют методы одного класса.
К примеру, мы можем иметь один класс, но он будет работать с базой/файловой системой и если у нас базай/файловая система как-то не замокана то получим в итоге интеграционный тест.
Самый типичный пример — тестирование ActiveRecord моделей унаследованных от базового ActiveRecord. Тест как-бы будет проверять один класс, но по факту мы будет тестировать заодно и кучу компонетнов ORM.
Если не совсем понятно к чему я клоню, могу привести примеры кодом.
Юнит тесты тестируют именно поведение классов. Модули, состоящие из множества классов тестируют интеграционными тестами.
Вот именно с этим я и спорю Интереса ради почитайте искусство автономного тестирования автор Рой Ошероув
Вот определение UnitTest которое он дает
Единица работы
— это совокупность действий от момента вызова какого-то
открытого метода в системе до единственного конечного результата, замет-
ного тесту системы. Этот конечный результат можно наблюдать, не исследуя
внутреннее состояние системы, а только с помощью открытых API и поведе-
ния.
Автономный тест – это часть кода, которая
вызывает единицу работы и затем проверяет ее конечный результат. Если
предположения о конечном результате не подтверждаются, считается, что
автономный тест завершился неудачно. Объектом автономного тестиро-
вания может быть как единственный метод, так и совокупность нескольких
классов.
Баги часто встречаются именно при взаимодействии классов. Если несколько классов предоставляют некую сущность которую можно протестировать вместе то лучше так и делать. И если вы считаете этот тест интеграционным, ну это ваше дело.
Цель За меньшее время написать тесты имеющие наибольшее покрытие.
вот к стати статья в которой автор рассуждает об интеграционных и юнит тестов https://habrahabr.ru/post/275249/
Меньше всего мне хочется спорить с кем бы то ни было о вкусах. У меня вообще нет такой цели: "За меньшее время написать тесты, имеющие наибольшее покрытие" потому что я всегда сначала пишу тест, а потом код. Я сначала пишу тесты потому что это:
- Улучшает внутренний дизайн и архитектуру программной системы
- Удешевляет и упрощает последующее изменение кода
- Порождает "исполняемую" документацию по коду, которая никогда не врет
- Упрощает повторное использование кода
- Снижает стоимость эксплуатации программной системы
Я работаю скорее по BDD начинаю проектировать на каком то достаточно высоком уровне и постепенно спускаюсь к более низкоуровневым конструкциям, но до тестов одного класса доходит редко обычно в случае если там какая то особо заумная функция есть.
И мотивация только одна сделать свою работу как можно лучше. А все что Вы перечислили это только дополнительные стимулы.
Главная задача для меня — получать удовольствие от программирования.
Что означает "начинаю проектировать на каком-то достаточно высоком уровне"?
Главная задача для меня — получать удовольствие от программирования.
Как бы это… тут мы как представители древнейшей профессии (приятно, да еще и деньги платят не малые).
А по поводу высоком уровне. В Зависимости от задачи отвечаю на вопросы
Что должно произойти в системе?
Как это может быть исполнено?
Ну и пишу соответствующие тесты и интерфейсы которые пока мокаются.
в дальнейшем заменяю моки реализацией.
В общем BDD
Утверждение что Написание тестов значительно увеличивает время разработки справедливо в первую очередь если UnitTest пишется на объекты низкого уровня.
Если разработчик не парится по поводу размера юнита, а пишет тесты исходя из здравого смысла, то возможно даже и сокращает.
Я просто обожаю эту фразу, «Написание тестов значительно увеличивает время разработки». Всегда, когда слышу ее возникает чувство, что люди которые такое говорят не писали приложений сложнее автогенерируемых.
Конечно, юные разработчики, которые и программировать нормально еще не умеют, будут затрачивать больше времени на разработку при написании тестов.
Но это и не секрет, что джуны все делют или дольше или не качественнее.
Если же говорить про разработчиков, которые понимают философию тестирования и уже разобрались как пользоваться тестовым фреймвокром, то при разумном написании тестов проиводительность только повысится.
На пимере веб-приложения.
Мы можем иметь класс, который обрабатывает данные с формы и выдает какой-то результат для дальнейшей обработки следующему классу.
Без теста мы можем вводить данные на форму, отправлять ее и смотреть что получим(может еще и дебажить в то же время).
С тестом мы просто введем нужные нам данные при написании теста и будем его запускать каждый раз когда хоти проверить правки.
От одного только сокращения времени на перезагруке страницы, вводде данных и ожидании ответа сервера можно выиграть не мало времени.
P.S. не подумайте, что я с Вами спорю — наоборот, поддерживаю Ваше высказывание
пишет тесты исходя из здравого смысла, то возможно даже и сокращает.
1. «толстые» тесты лично у меня как правило получаются когда метод делает много операций, типа «ReadAndApply»:
public DoMagic()
{
DoAbra();
DoCadabra();
}
Но внутренние методы не хочется показывать наружу тк их могут использовать (а не надо). Поэтому приходится делать наследника и тюкать их как protected. Что иногда «доставляет». Или делать 100500 хелперов.
2. Как не писать фригильные тесты это целая наука и нигде толком не описано. В один прекрасный день одно небольшое изменение можеть сломать столько тестов, которые компилиться откажутся, не то, что проходить :) Постигается только потом и болью (и переписыванием фикстур).
3. Вопрос знатокам. В .Net чтобы мокить класс должен или быть абстрактным или интерфейсным.
В MVVM понятно как тестировать модель. InMemory база и все летает. Тестировать ViewModel даже на такой датабазе кажется странной идей поэтому у меня каждая модель имплементирует свой интерфейс и он соотв. мокится. Это нормально или я усложняю?
и если ваш сервис — это не обычный, играющий музыку на фоне сервис, а какой-то интент-сервис, который реагирует на бродкасты и так далее, здесь он уже не поможет, придется выкручиваться самим.
Вот как раз открыл статью что бы прочиать о тестировании интент-сервисов, бродкастов, handleMessage, EventBus и прочей асинхронщины, но не судьба…
А в чем проблема то с тестированием "асинхронщины"?
Иногда, в случае активного использования вашего модуля кем-то другим — необходимое.
С тестами есть следующие проблемы:
- на их написание уходит время
- на их вдумчивое продумывание уходит крайне длительное время
- они ломаются вместе с изменением API
- их использование, даже после того, как они написаны — отнюдь не бесплатно
Понятно, что если вы реализуете какую-нибудь матричную арифметику, в которой может быть куча corner cases, то без большого объёма всеобъемлющих тестов не обойтись — но часто ли вы изобретаете такие велосипеды?
При этом, многие из тестов — абсолютно не нужны!
Есть ли смысл каждый раз проверять что 2+2=4, если любая ошибка в этом выражении — достаточно тривиальная, чтобы её поймал юнит-тест — и так будет сразу же обнаружена при использовании программы?
Поэтому для себя я решил — тесты у меня в программах должны создаваться практически полностью автоматически, причём только тогда, когда уже выявлено наличие в коде бага — и написан тест должен быть так, чтобы как раз выяснить детали проявления этого бага.
Для этого синтаксис тестов у меня полностью совпадает с синтаксисом системы логирования: запустил программу в debug-режиме, скопировал кусок дебажного вывода в тестовый проект — и тест готов.
В четвертом не понятно, что конкретно имелли ввиду? Процессорное время?
Для этого синтаксис тестов у меня полностью совпадает с синтаксисом системы логирования: запустил программу в debug-режиме, скопировал кусок дебажного вывода в тестовый проект — и тест готов.
Можно подробнее, что подразумеваете под тестовым проектом?
В четвёртом не понятно, что конкретно имели ввиду? Процессорное время?И оно тоже (полная проверка кода с множественными ветвлениями может занимать очень длительное время, если вообще осуществима), но больше время того, кто тестирует, и того, кто получает с него отчёты. Чаще всего эта проблема — как следствие пункта 3.
Можно подробнее, что подразумеваете под тестовым проектом?В моём случае — шаблонный проект QT Unit test. Отфильтрованные логи вызова функций для проверяемого класса вставляются прямо внутрь функций test_case().
1 и 2 Как уже писалось в обсуждении этой статьи тесты при правильном использовании экономят время даже во время разработки.
3 Если изменилось API. Нарушение от принципа открытости закрытости. Ну как бы бывает конечно такая необходимость но сравнительно редко. И тогда новое API Надо тестировать.
4 Да не бесплатно за все надо платить
Тесты гоняются на сервере и жрут сволочи электричество ( посчитайте сколько интереса ради) Ну и иногда находят ошибки которые увы надо править. Что то же занимает время и иногда раздражает. Ну вроде бы все сделал а тут ошибка за ошибкой.
А вот про авто написание тестов это интересная мысль. Хотя и не понял толком что там происходит.
по Вашим словам я понял что вы ухитрились так написать Лог что бы он имитировал вызов функции с параметрами которые были преданы.
Это должно быть сделано автоматически Вызвал в начале каждого метода функцию типа Log.AutoTraiсe и готово
Если это на Net то Если можно дайте образец кода
Практика написания тестов. Лекция Яндекса