Открыть список
Как стать автором
Обновить

Комментарии 24

В общем все правильно но пару маленьких замечаний.
1) Статья некая обзорная лекция о тестировании применимая думаю на любой платформе и любом языке.
Зачем в заглавии слово Android?
2) Скорее вопрос. Я согласен с определениием юнит тестов.
Но скажите пожалуйста у Вас в фирме при написании тестов действительно «Чаще всего в качестве юнита выбирается какой-либо класс».
Думаю, что это скорее исключениие. Реально выбирается модуль состоящий обычно из множества классов.
Ну для примера можно скачать с GitHab нескольно приложений в который есть тесты.
Специально я не исследовал, но на вскидку не нашел ни одного в котором тестировался бы каждый класс отдельно.
Почему я на это обратил внимание?
В фирме где я работаю начитались таких утверждений и считают это образцом.
Ну а так как классов у нас тысячи (порядка 5 000) и в каждом классе минимум пять функций,
то написание Юнит тестов это хотя и надо, но непозволительно долго.
3) Утверждение что Написание тестов значительно увеличивает время разработки справедливо в первую очередь если UnitTest пишется на объекты низкого уровня.
Если разработчик не парится по поводу размера юнита, а пишет тесты исходя из здравого смысла, то возможно даже и сокращает.

Юнит тесты тестируют именно поведение классов. Модули, состоящие из множества классов тестируют интеграционными тестами.


Классический подход прост. Сначала пишем тест, потом пишем код, поведение которого проверяется в тесте. Ну а поведенческий код в объектно-ориентированной парадигме обычно упаковывается в класс. Поэтому юнит тесты обычно тестируют методы одного класса.

добавлю важный момент — юнит тесты должны быть максимально независимы от окружения.

К примеру, мы можем иметь один класс, но он будет работать с базой/файловой системой и если у нас базай/файловая система как-то не замокана то получим в итоге интеграционный тест.

Самый типичный пример — тестирование ActiveRecord моделей унаследованных от базового ActiveRecord. Тест как-бы будет проверять один класс, но по факту мы будет тестировать заодно и кучу компонетнов ORM.

Если не совсем понятно к чему я клоню, могу привести примеры кодом.

ActiveRecord на мой взгляд — антишаблон. Модель данных не должна зависеть от механизмов хранения.

Юнит тесты тестируют именно поведение классов. Модули, состоящие из множества классов тестируют интеграционными тестами.

Вот именно с этим я и спорю Интереса ради почитайте искусство автономного тестирования автор Рой Ошероув
Вот определение UnitTest которое он дает

Единица работы
— это совокупность действий от момента вызова какого-то
открытого метода в системе до единственного конечного результата, замет-
ного тесту системы. Этот конечный результат можно наблюдать, не исследуя
внутреннее состояние системы, а только с помощью открытых API и поведе-
ния.
Автономный тест – это часть кода, которая
вызывает единицу работы и затем проверяет ее конечный результат. Если
предположения о конечном результате не подтверждаются, считается, что
автономный тест завершился неудачно. Объектом автономного тестиро-
вания может быть как единственный метод, так и совокупность нескольких
классов.

Баги часто встречаются именно при взаимодействии классов. Если несколько классов предоставляют некую сущность которую можно протестировать вместе то лучше так и делать. И если вы считаете этот тест интеграционным, ну это ваше дело.
Цель За меньшее время написать тесты имеющие наибольшее покрытие.
вот к стати статья в которой автор рассуждает об интеграционных и юнит тестов https://habrahabr.ru/post/275249/

Меньше всего мне хочется спорить с кем бы то ни было о вкусах. У меня вообще нет такой цели: "За меньшее время написать тесты, имеющие наибольшее покрытие" потому что я всегда сначала пишу тест, а потом код. Я сначала пишу тесты потому что это:


  • Улучшает внутренний дизайн и архитектуру программной системы
  • Удешевляет и упрощает последующее изменение кода
  • Порождает "исполняемую" документацию по коду, которая никогда не врет
  • Упрощает повторное использование кода
  • Снижает стоимость эксплуатации программной системы
К стати я тоже стараюсь сначала писать тесты только мотивация у меня совсем не такая.
Я работаю скорее по BDD начинаю проектировать на каком то достаточно высоком уровне и постепенно спускаюсь к более низкоуровневым конструкциям, но до тестов одного класса доходит редко обычно в случае если там какая то особо заумная функция есть.
И мотивация только одна сделать свою работу как можно лучше. А все что Вы перечислили это только дополнительные стимулы.

Главная задача для меня — получать удовольствие от программирования.


Что означает "начинаю проектировать на каком-то достаточно высоком уровне"?

Главная задача для меня — получать удовольствие от программирования.

Как бы это… тут мы как представители древнейшей профессии (приятно, да еще и деньги платят не малые).
А по поводу высоком уровне. В Зависимости от задачи отвечаю на вопросы
Что должно произойти в системе?
Как это может быть исполнено?
Ну и пишу соответствующие тесты и интерфейсы которые пока мокаются.
в дальнейшем заменяю моки реализацией.
В общем BDD
Утверждение что Написание тестов значительно увеличивает время разработки справедливо в первую очередь если UnitTest пишется на объекты низкого уровня.
Если разработчик не парится по поводу размера юнита, а пишет тесты исходя из здравого смысла, то возможно даже и сокращает.

Я просто обожаю эту фразу, «Написание тестов значительно увеличивает время разработки». Всегда, когда слышу ее возникает чувство, что люди которые такое говорят не писали приложений сложнее автогенерируемых.

Конечно, юные разработчики, которые и программировать нормально еще не умеют, будут затрачивать больше времени на разработку при написании тестов.
Но это и не секрет, что джуны все делют или дольше или не качественнее.

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

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

Без теста мы можем вводить данные на форму, отправлять ее и смотреть что получим(может еще и дебажить в то же время).

С тестом мы просто введем нужные нам данные при написании теста и будем его запускать каждый раз когда хоти проверить правки.

От одного только сокращения времени на перезагруке страницы, вводде данных и ожидании ответа сервера можно выиграть не мало времени.

P.S. не подумайте, что я с Вами спорю — наоборот, поддерживаю Ваше высказывание
пишет тесты исходя из здравого смысла, то возможно даже и сокращает.
Так то оно так но есть к сожалению троглодиты которые книжек ни читают и тесты не пишут
Классная лекция. Узнал много интересного.
Я пишу под .Net, но тут одна фигня, поэтому задам парочку вопросов :)

1. «толстые» тесты лично у меня как правило получаются когда метод делает много операций, типа «ReadAndApply»:
public DoMagic()
{
DoAbra();
DoCadabra();
}

Но внутренние методы не хочется показывать наружу тк их могут использовать (а не надо). Поэтому приходится делать наследника и тюкать их как protected. Что иногда «доставляет». Или делать 100500 хелперов.

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

3. Вопрос знатокам. В .Net чтобы мокить класс должен или быть абстрактным или интерфейсным.
В MVVM понятно как тестировать модель. InMemory база и все летает. Тестировать ViewModel даже на такой датабазе кажется странной идей поэтому у меня каждая модель имплементирует свой интерфейс и он соотв. мокится. Это нормально или я усложняю?

Ответы на ваши вопросы есть в книгах Роберта Мартина, Кента Бека и "банды четерех" (Эрих Гамма, Ричард Хелм, Ральф Джонсон, Джон Влиссидес).

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

Вот как раз открыл статью что бы прочиать о тестировании интент-сервисов, бродкастов, handleMessage, EventBus и прочей асинхронщины, но не судьба…

А в чем проблема то с тестированием "асинхронщины"?

Тем что проверять работу посылки сообщения порой необходимо в другом потоке а иногда и другом процессе.

Не вижу особых проблем с реализацией подобных тестовых сценариев. Может конечно у вас какой-то неожиданно особый environment, без примеров кода сложно судить.

Тесты — зло.
Иногда, в случае активного использования вашего модуля кем-то другим — необходимое.
С тестами есть следующие проблемы:
  1. на их написание уходит время
  2. на их вдумчивое продумывание уходит крайне длительное время
  3. они ломаются вместе с изменением API
  4. их использование, даже после того, как они написаны — отнюдь не бесплатно

Понятно, что если вы реализуете какую-нибудь матричную арифметику, в которой может быть куча corner cases, то без большого объёма всеобъемлющих тестов не обойтись — но часто ли вы изобретаете такие велосипеды?
При этом, многие из тестов — абсолютно не нужны!
Есть ли смысл каждый раз проверять что 2+2=4, если любая ошибка в этом выражении — достаточно тривиальная, чтобы её поймал юнит-тест — и так будет сразу же обнаружена при использовании программы?
Поэтому для себя я решил — тесты у меня в программах должны создаваться практически полностью автоматически, причём только тогда, когда уже выявлено наличие в коде бага — и написан тест должен быть так, чтобы как раз выяснить детали проявления этого бага.

Для этого синтаксис тестов у меня полностью совпадает с синтаксисом системы логирования: запустил программу в debug-режиме, скопировал кусок дебажного вывода в тестовый проект — и тест готов.
C первыми тремя пунктами солидарен с вами.
В четвертом не понятно, что конкретно имелли ввиду? Процессорное время?
Для этого синтаксис тестов у меня полностью совпадает с синтаксисом системы логирования: запустил программу в debug-режиме, скопировал кусок дебажного вывода в тестовый проект — и тест готов.

Можно подробнее, что подразумеваете под тестовым проектом?
В четвёртом не понятно, что конкретно имели ввиду? Процессорное время?
И оно тоже (полная проверка кода с множественными ветвлениями может занимать очень длительное время, если вообще осуществима), но больше время того, кто тестирует, и того, кто получает с него отчёты. Чаще всего эта проблема — как следствие пункта 3.
Можно подробнее, что подразумеваете под тестовым проектом?
В моём случае — шаблонный проект QT Unit test. Отфильтрованные логи вызова функций для проверяемого класса вставляются прямо внутрь функций test_case().

Не видел еще ни одного проекта, где к примеру модульные тесты занимали бы хоть сколько-нибудь значительное время. Около 3000 модульных тестов в проекте бэкенда, написанного на C# с использованием ASP.NET занимало несколько секунд.

НЕ согласен по всем пунктам.
1 и 2 Как уже писалось в обсуждении этой статьи тесты при правильном использовании экономят время даже во время разработки.
3 Если изменилось API. Нарушение от принципа открытости закрытости. Ну как бы бывает конечно такая необходимость но сравнительно редко. И тогда новое API Надо тестировать.
4 Да не бесплатно за все надо платить
Тесты гоняются на сервере и жрут сволочи электричество ( посчитайте сколько интереса ради) Ну и иногда находят ошибки которые увы надо править. Что то же занимает время и иногда раздражает. Ну вроде бы все сделал а тут ошибка за ошибкой.

А вот про авто написание тестов это интересная мысль. Хотя и не понял толком что там происходит.
по Вашим словам я понял что вы ухитрились так написать Лог что бы он имитировал вызов функции с параметрами которые были преданы.
Это должно быть сделано автоматически Вызвал в начале каждого метода функцию типа Log.AutoTraiсe и готово
Если это на Net то Если можно дайте образец кода
СОГЛАСЕН по всем пунктам.
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

Информация

Дата основания
Местоположение
Россия
Сайт
www.yandex.ru
Численность
свыше 10 000 человек
Дата регистрации

Блог на Хабре