Комментарии 50
Кстати, написание юнит-тестов к готовому коду — один из лучших способов изучить этот самый код. Принимая на работу человека, мы даем ему от 2 недель до 2 месяцев на написание тестов для отдельных частей системы. Работает очень хорошо.
+2
Это если повезёт :-) Для того, чтобы можно было протестировать код — изначально код должен быть написан с расчётом на то, что он будет когда-то покрыт тестами, ну или просто быть достаточно качественным.
+7
Согласен.
Юнит-тесты у нас есть — и всегда можно найти, что еще бы потестировать. Тут почти нет пределов — возможно, это специфика области (движок базы данных)
А идти в проект, где куча кода и нет тестов — это как плохому учиться: легко и просто, но и пользы никакой.
Юнит-тесты у нас есть — и всегда можно найти, что еще бы потестировать. Тут почти нет пределов — возможно, это специфика области (движок базы данных)
А идти в проект, где куча кода и нет тестов — это как плохому учиться: легко и просто, но и пользы никакой.
0
А вот тут Вы не правы.
В данном случае можно научиться пошаговому рефакторингу из самых ужасных ситуаций.
В данном случае можно научиться пошаговому рефакторингу из самых ужасных ситуаций.
+5
Это ваш опыт за плечами говорит.
Бывает код, который можно рефакторить-рефакторить, да не вырефакторить. В таких случаях нужен профессионал, который сам многому научит, который придет и перепишет «как надо».
А студента, у которого опыта с пару курсовых, так «человеком» не сделать, нужно хорошие примеры: код, тесты, процесс, обучение.
Бывает код, который можно рефакторить-рефакторить, да не вырефакторить. В таких случаях нужен профессионал, который сам многому научит, который придет и перепишет «как надо».
А студента, у которого опыта с пару курсовых, так «человеком» не сделать, нужно хорошие примеры: код, тесты, процесс, обучение.
+2
Я даже не знаю, кто из вас сейчас сильнее прав. Я сейчас работаю на проекте, который изначально был… Мм… Фаршем. Простые примеры:
— ни одного теста. То есть, вообще. Совсем. Тупо нет и всё.
— код пестрит чем-то типа String Rabota = «1»; это такое, до сих пор не очень понял
— коммиты почти всегда идут без комментов
— иногда натыкаешься на 200 строк закомментированого кода и не понятно что это, зачем и почему оставлено
— ну и так далее. Все подробности описывать не буду.
Опыта у меня довольно мало, чуть больше, чем пол года. Но на предыдущем месте работы всё было «по феншую»: начиная от багтракера, которого тут тупо нет, заканчивая строгим Code Policy.
В общем, к чему это я… начинал изучение этого самого проекта я именно с тестов, в смысле, что сам писал. Помимо того, что начал хоть немного врубаться, как это устроено, нашел кучку багов, которые тут же фиксил. Но для того, чтобы привести тут всё в порядок — надо просто всё переписывать. С нуля.
— ни одного теста. То есть, вообще. Совсем. Тупо нет и всё.
— код пестрит чем-то типа String Rabota = «1»; это такое, до сих пор не очень понял
— коммиты почти всегда идут без комментов
— иногда натыкаешься на 200 строк закомментированого кода и не понятно что это, зачем и почему оставлено
— ну и так далее. Все подробности описывать не буду.
Опыта у меня довольно мало, чуть больше, чем пол года. Но на предыдущем месте работы всё было «по феншую»: начиная от багтракера, которого тут тупо нет, заканчивая строгим Code Policy.
В общем, к чему это я… начинал изучение этого самого проекта я именно с тестов, в смысле, что сам писал. Помимо того, что начал хоть немного врубаться, как это устроено, нашел кучку багов, которые тут же фиксил. Но для того, чтобы привести тут всё в порядок — надо просто всё переписывать. С нуля.
+3
Суть подхода и опыт работы в таком процессе у вас есть, это хорошо. Теперь вам надо двигаться в сторону работы с legacode, его модернизации, тестирование и рефакторинг. Процесс не легкий. Иногда кажется что все выкинуть и написать с нуля будет лучшем решением, но это не так.
0
| legacode
А можно чуть подробнее? Куда копать, что почитать, и т.д. Впервые слышу подобный термин :(
А можно чуть подробнее? Куда копать, что почитать, и т.д. Впервые слышу подобный термин :(
0
Сори, может ввел немного в заблуждение. Я имел в виду legacy code. Обычно так называют код который достался в наследство :) И имеет ряд недостатков:
— Например такой код тяжело модернизировать.
— Такой код тяжело поддается тестированию.
— Код работает но чтобы понять почему, уходить много времени
— и так далее.
Думаю начать нужна с этой книги Michael Feather «Working Effectively with Legacy Code». Далее великий интернет вам поможет :)
— Например такой код тяжело модернизировать.
— Такой код тяжело поддается тестированию.
— Код работает но чтобы понять почему, уходить много времени
— и так далее.
Думаю начать нужна с этой книги Michael Feather «Working Effectively with Legacy Code». Далее великий интернет вам поможет :)
0
Ну вообще написание тестов по готовому коду немного противоречит TDD, тесты же должны писаться до разработки функционала. Но соглашусь с тем, что это в идеале, т.к. очень часто приходится дописывать неучтенные тесты, или даже внедрять тестирование на уже запущенных проектах.
А по-поводу новых сотрудников мы работали несколько иначе. Приходил человек, мы его подсаживали в пару к другому разработчику, как результат человек за 2 — 3 недели въезжал в проект, а также быстрее вливался в коллектив =)
А по-поводу новых сотрудников мы работали несколько иначе. Приходил человек, мы его подсаживали в пару к другому разработчику, как результат человек за 2 — 3 недели въезжал в проект, а также быстрее вливался в коллектив =)
+1
Ну, по этому поводу тоже много кто писал. XP, парное программирование )) У нас на старой работе ребята как-то чуть не подрались, сидя за одним компом )) До сих пор вспоминаем :)
0
И пускай кто-то скажет, что парное программирование не экстремально :)
+2
А у нас на работе все программируют в пара, и это отлично работает. Это как доказательство того, что XP — это хорошо. А тот факт, что у вас это один раз не получилось, вовсе не доказывает, что XP — это плохо.
0
Кстати да! Хорошие способы, но вопрос «с чего же начать?» так и не раскрыт, на мой взгляд. Помню себя в те мучительные времена становления вопросов ТДД в голове и могу только посоветовать начинающим курить эту классику до тех пор, пока в голове не «щелкнет». Лично мне только она помогла.
+2
Начинать полезно с интерфейсов )
Я лично когда начинаю писать какой-либо более-мелее отделенный от остальной системы функционал, всегда вначале создаю несколько интерфейсов, с которыми клиент этой части системы может работать. После этого тесты на этот интерфейс напрашиваются сами.
Это хорошо работает для обособенной логики. Если же нужно протестить Web, EJB и т.д., то используем мощь соответствующего framework'а. Как правило, сейчас даже в мануалах есть разделы «как это тестировать».
Я лично когда начинаю писать какой-либо более-мелее отделенный от остальной системы функционал, всегда вначале создаю несколько интерфейсов, с которыми клиент этой части системы может работать. После этого тесты на этот интерфейс напрашиваются сами.
Это хорошо работает для обособенной логики. Если же нужно протестить Web, EJB и т.д., то используем мощь соответствующего framework'а. Как правило, сейчас даже в мануалах есть разделы «как это тестировать».
0
Здоровски! :) Читается просто на одном дыхании. Действительно, самое сложное — это начать писать тесты. И по моему мнению, Вы отлично показали как это можно сделать. Спасибо!
+1
Толково расписано, понятным языком.
0
Расписано, безусловно, толково, но это не TDD. Как было верно указано в начале статьи, тест должен не тестировать, а описывать поведение программы. Т.е. тест должен придумываться задолго до коммита или вопроса начальника. Написали тест — написали код — подтвердили прохождение теста — закоммитили.
Сами тесты же должны браться из ТЗ, спеки или переговоров с заказчиком. Вы же, в конце концов, знаете, что должна делать ваша программа — ну так и описывайте. Лично для себя я выбрал метод «от общего к частному». Т.е. сначала я описываю общий функционал отдельного модуля/страницы, затем, по выполнении общих тестов, описываю мелкие детали и частные случаи. Если эти тесты валятся — правлю код. Это очень удобно, т.к. не требует изначального утомительного описывания каждого чиха программы.
Сами тесты же должны браться из ТЗ, спеки или переговоров с заказчиком. Вы же, в конце концов, знаете, что должна делать ваша программа — ну так и описывайте. Лично для себя я выбрал метод «от общего к частному». Т.е. сначала я описываю общий функционал отдельного модуля/страницы, затем, по выполнении общих тестов, описываю мелкие детали и частные случаи. Если эти тесты валятся — правлю код. Это очень удобно, т.к. не требует изначального утомительного описывания каждого чиха программы.
+3
хорошая статья, еще раз убедился принял правильное решение о написании юнит тестов в своей программе
0
Уже, по-моему, 3-я статья за последние пару недель о юнит-тестах, где путается тёплое с мягким: заголовок про юнит-тесты, обязательное упоминание TDD, а затем и функциональные-приёмочные тесты до кучи (при этом ни слова о подходе самого TDD).
+4
> Каждое утро на собрании начальник спрашивает тебя: «Что ты вчера делал?».
> — Багу исправлял.
Автор целый день исправлял багу в одном методе! Налицо эффективность TDD! Это не просто язвительное замечание. Производительность людей, зацикленных на TDD, реально такая. И ничего сложней валидатора они как правило не пишут. Вы хоть примеры-то для разнообразия поинтересней придумайте, а то одни валидаторы…
> — Слушай, я тут твой код дебажу-дебажу, а всё никак не могу понять, как это работает?
Так надо было по-русски прямо в коде и написать:
/** Энкодит букву по алгоритму:…
Например если на вход подать А, то получится Б */
public String encodeLetter( String letter )
Да-да, прямо в коде, не надо бояться! И ошибки не будет, и лишний тест не надо писать, и коллега сразу сообразит что к чему. Это называется контрактом. А в Вашем случае прекрасно сработает и это:
public String encodeLetter( String letter ) { return «Б» }
И будет соответствовать «спецификации».
> assertTrue(validateEmail(«tina.turner@music.info»)); // 4 letters now allowed!
Где спецификация самого метода? С каких хренов 4 буквы not allowed? Где это написано? При чем тут тесты? А 5 буквами как дела обстоят? А с доменом-поддоменом? Рановато +1 в карму…
> — Багу исправлял.
Автор целый день исправлял багу в одном методе! Налицо эффективность TDD! Это не просто язвительное замечание. Производительность людей, зацикленных на TDD, реально такая. И ничего сложней валидатора они как правило не пишут. Вы хоть примеры-то для разнообразия поинтересней придумайте, а то одни валидаторы…
> — Слушай, я тут твой код дебажу-дебажу, а всё никак не могу понять, как это работает?
Так надо было по-русски прямо в коде и написать:
/** Энкодит букву по алгоритму:…
Например если на вход подать А, то получится Б */
public String encodeLetter( String letter )
Да-да, прямо в коде, не надо бояться! И ошибки не будет, и лишний тест не надо писать, и коллега сразу сообразит что к чему. Это называется контрактом. А в Вашем случае прекрасно сработает и это:
public String encodeLetter( String letter ) { return «Б» }
И будет соответствовать «спецификации».
> assertTrue(validateEmail(«tina.turner@music.info»)); // 4 letters now allowed!
Где спецификация самого метода? С каких хренов 4 буквы not allowed? Где это написано? При чем тут тесты? А 5 буквами как дела обстоят? А с доменом-поддоменом? Рановато +1 в карму…
-1
Откуда столько ненависти?
Да, это нормально исправлять целый день один метод, даже если вы не пишете юнит-тесты, просто методы и их сложность бывают разные. В статье простой и подходящий пример — валидация.
Нет, не нужно в коде писать по-русски, это же код а не художественный роман, пишите на английском хотя бы.
Да, это нормально исправлять целый день один метод, даже если вы не пишете юнит-тесты, просто методы и их сложность бывают разные. В статье простой и подходящий пример — валидация.
Нет, не нужно в коде писать по-русски, это же код а не художественный роман, пишите на английском хотя бы.
+5
Откуда столько ненависти?
Да, это нормально исправлять целый день один метод, даже если вы не пишете юнит-тесты, просто методы и их сложность бывают разные. В статье простой и подходящий пример — валидация.
Нет, не нужно в коде писать по-русски, это же код а не художественный роман, пишите на английском хотя бы.
Да, это нормально исправлять целый день один метод, даже если вы не пишете юнит-тесты, просто методы и их сложность бывают разные. В статье простой и подходящий пример — валидация.
Нет, не нужно в коде писать по-русски, это же код а не художественный роман, пишите на английском хотя бы.
0
Откуда столько ненависти?
Да, это нормально исправлять целый день один метод, даже если вы не пишете юнит-тесты, просто методы и их сложность бывают разные. В статье простой и подходящий пример — валидация.
Нет, не нужно в коде писать по-русски, это же код а не художественный роман, пишите на английском хотя бы.
Да, это нормально исправлять целый день один метод, даже если вы не пишете юнит-тесты, просто методы и их сложность бывают разные. В статье простой и подходящий пример — валидация.
Нет, не нужно в коде писать по-русски, это же код а не художественный роман, пишите на английском хотя бы.
-3
а у меня не получается писать юнит-тесты:
1. Их обычно пишут на public методы, а у меня public метод только один для класса. Все остальные private
2. Подготовить данные для тестирования бизнес-логики настоящая проблема, потому что надо сгенерировать сложнейшие связи в базе данных, которые зависимы друг от друга.
3. Написать скрипт длиной в несколько сотен строк, генерирующий данные, мне просто знаний sql не хватит.
4. Объяснять спецу по базам данных что мне надо, а потом еще 20 раз попросить исправить что-то в скрипте — займет 90% от выделенного мне на задачу времени.
5. Иметь каждому разработчику отдельную базу и синхронизировать у нас не принято, да и не удобном опять же по причине синхронизации и написания полотен sql скриптов.
Вот и выходит, что тестировать не удобно юнит тестами, а учитывая, что мы используем не простые sql запросы, а fluent nhibernate, то создать объект внутри базы становится непосильной задачей, т.к. объект не будет записан в базу (ссылка на null в базе) до тех пор, пока мы создадим еще 100500 подобъектов
Писать тесты для валидации или работа со строками — это просто, а что делать со связями в БД не знаю.
А я очень хочу писать тесты, но как решить проблему не знаю.
1. Их обычно пишут на public методы, а у меня public метод только один для класса. Все остальные private
2. Подготовить данные для тестирования бизнес-логики настоящая проблема, потому что надо сгенерировать сложнейшие связи в базе данных, которые зависимы друг от друга.
3. Написать скрипт длиной в несколько сотен строк, генерирующий данные, мне просто знаний sql не хватит.
4. Объяснять спецу по базам данных что мне надо, а потом еще 20 раз попросить исправить что-то в скрипте — займет 90% от выделенного мне на задачу времени.
5. Иметь каждому разработчику отдельную базу и синхронизировать у нас не принято, да и не удобном опять же по причине синхронизации и написания полотен sql скриптов.
Вот и выходит, что тестировать не удобно юнит тестами, а учитывая, что мы используем не простые sql запросы, а fluent nhibernate, то создать объект внутри базы становится непосильной задачей, т.к. объект не будет записан в базу (ссылка на null в базе) до тех пор, пока мы создадим еще 100500 подобъектов
Писать тесты для валидации или работа со строками — это просто, а что делать со связями в БД не знаю.
А я очень хочу писать тесты, но как решить проблему не знаю.
+1
В таких случаях используются фабрики и генераторы фейковых объектов для наполнения тестовой базы. Да, кстати, о тестовой базе. Она должна быть в любом случае.
В инструментах на PHP, к сожалению, не искушен, но можете посмотреть FFaker и Fabricator для Ruby, чтобы понять, о чем я говорю.
В инструментах на PHP, к сожалению, не искушен, но можете посмотреть FFaker и Fabricator для Ruby, чтобы понять, о чем я говорю.
0
1. Их обычно пишут на public методы, а у меня public метод только один для класса. Все остальные private
Не функции покрываются, а их код. Тестируйте публичный метод, но так чтобы каждая приватная (точнее каждый блок каждой функции) был бы вызван. Если бы использовали TBC то так бы и вышло.
2. Подготовить данные для тестирования бизнес-логики настоящая проблема, потому что надо сгенерировать сложнейшие связи в базе данных, которые зависимы друг от друга.
Это значит много: во-1, вы скипнули юнит-тесты и пишете уже интеграционный тест. Это вследствие (неиспользования TBC и, как результат) того что объекты у вас тесно связаны, курите dependency invertion. В третьих, (а от этого и ваши 3й и 4й пункты) возможно нарушен принцип single responsibility — объект должен моделью создаваться (скажем одним вызовом addObject()), какой SQL при этом генерируется — его личное инкапсулированное дело. Вы же ведь не достаете данные напрямую из базы, через геттеры ведь достаете (нет?)
5. Иметь каждому разработчику отдельную базу и синхронизировать у нас не принято, да и не удобном опять же по причине синхронизации и написания полотен sql скриптов.Ну а это уже совсем напрасно. Один рефакторит/валит базу остальные в это время курят? Разве сложно вынести имя базы в конфиг? Впрочем, я не знаю особенностей вашего приложения.
0
2DarthSim
я пишу для .net. Боюсь что сложность бизнеслогики не позволит использовать автогенераторы данных. граничные и фейковые значение мне не столь сложно проверить, как соответствие дат, денежных сумм, наличия/отсутсвия связей и т.д.
2denver
простите, но я понял (язык и терминологию не понял) что вы написали в п.2 Прошу вас, объясните подробнее.
Объект-то базы создается моделью. Только вот чтобы заполнить все поля объекта (банковское ПО у нас) и найти все связи таблиц (не просто состояния или типы, а до 30 различных логических связей и взаимодействий таблиц) можно потратить несколько дней на такие заготовки для 1 нового класса бизнес-логики по автоматизации чего либо.
т.е. не получается просто сделать 2-3 вызова paymentsRepository.AddObject(newPaymentFromCustomer)
и тем самым сгенерировать данные.
Поэтому честно сказать я не знаю, что с этим делать.
to ALL
Я правильно понял, что все заливают тестовые данные из файлов перед каждым запуском юнит теста? Ну тогда чем это лучше чем скрипты с запросами к БД.
я пишу для .net. Боюсь что сложность бизнеслогики не позволит использовать автогенераторы данных. граничные и фейковые значение мне не столь сложно проверить, как соответствие дат, денежных сумм, наличия/отсутсвия связей и т.д.
2denver
простите, но я понял (язык и терминологию не понял) что вы написали в п.2 Прошу вас, объясните подробнее.
Объект-то базы создается моделью. Только вот чтобы заполнить все поля объекта (банковское ПО у нас) и найти все связи таблиц (не просто состояния или типы, а до 30 различных логических связей и взаимодействий таблиц) можно потратить несколько дней на такие заготовки для 1 нового класса бизнес-логики по автоматизации чего либо.
т.е. не получается просто сделать 2-3 вызова paymentsRepository.AddObject(newPaymentFromCustomer)
и тем самым сгенерировать данные.
Поэтому честно сказать я не знаю, что с этим делать.
to ALL
Я правильно понял, что все заливают тестовые данные из файлов перед каждым запуском юнит теста? Ну тогда чем это лучше чем скрипты с запросами к БД.
0
По феншую, если для юнит-теста нужна база, то это либо тестирование модуля работы с базой (но не модели предметной области приложения), либо это не юнит-тест :)
Объект базы не должен создаваться моделью, по крайней мере захардкодено, объект или класс базы должен задаваться извне класса модели (в конструкторе, в сеттере, в конфиге, где-то ещё), так чтобы можно было перед сохранением модели изменить собственно хранилище (от параметров вроде имени БД/логина до класса этого хранилища, например заменить БД на memcached или вообще на фэйковый объект — mock)
Объект базы не должен создаваться моделью, по крайней мере захардкодено, объект или класс базы должен задаваться извне класса модели (в конструкторе, в сеттере, в конфиге, где-то ещё), так чтобы можно было перед сохранением модели изменить собственно хранилище (от параметров вроде имени БД/логина до класса этого хранилища, например заменить БД на memcached или вообще на фэйковый объект — mock)
+1
НЛО прилетело и опубликовало эту надпись здесь
Про пункты №№2 и 3
1. Mock-objects
2. Yaml/XML/JSON — DB
3. Migrations
Посредством миграций тестовая юаза наполняется идеальными (и нет) данными из файликов. Для проверки кода, использующего внешние зависимости (RPC, SOAP, REST) зависимости перекрываются моками и проверяется, что именно они вызвались.
1. Mock-objects
2. Yaml/XML/JSON — DB
3. Migrations
Посредством миграций тестовая юаза наполняется идеальными (и нет) данными из файликов. Для проверки кода, использующего внешние зависимости (RPC, SOAP, REST) зависимости перекрываются моками и проверяется, что именно они вызвались.
+1
у нас была специальная тестовая база,
создавалась из дампа перед запуском каждого теста
в конце теста — уничтожалась
специальный скрипт для запуска тестов, который запускал тестовую БД, гонял тесты и дропал БД.
недостаток: одновременно нельзя было запустить два теста.
создавалась из дампа перед запуском каждого теста
в конце теста — уничтожалась
специальный скрипт для запуска тестов, который запускал тестовую БД, гонял тесты и дропал БД.
недостаток: одновременно нельзя было запустить два теста.
0
Вот читаю, читаю я статьи на Хабре про TDD и BDD и никак вкурить не могу… Примеры приводятся достаточно элементарные, а вот что-то реально нужного никак не могу прочитать.
Давайте рассмотрим банальный подход по принципу BLL->DAL->DB. Предположим у нас GridView отображает данные возвращаемые одним из методов одного из классов неймспейса BLL. Каким образом писать эти тесты для элементарного получения DataTable из базы и тем что должно получится? Писать сравнение каждой строчки возвращаемой? Или мы интерфейс не тестируем? А что мы тогда тестируем? А как тестировать вставку данных? Опять же для проверки формы из 10 полей (пусть все обязательные) какого же размера тест надо написать для разнообразных комбинаций?
Давайте рассмотрим банальный подход по принципу BLL->DAL->DB. Предположим у нас GridView отображает данные возвращаемые одним из методов одного из классов неймспейса BLL. Каким образом писать эти тесты для элементарного получения DataTable из базы и тем что должно получится? Писать сравнение каждой строчки возвращаемой? Или мы интерфейс не тестируем? А что мы тогда тестируем? А как тестировать вставку данных? Опять же для проверки формы из 10 полей (пусть все обязательные) какого же размера тест надо написать для разнообразных комбинаций?
+2
тестировать UI — очень непростая задача.
Тесты — это фактически проверка на соответствие требованиям. И если требования к классам легко описываются ассертами, то требования к UI формально описать очень сложно. Отсюда и сложность тестирования.
Работа с базой… модели работы с данными могут быть протестированы с использованием тестовых фикстур данных.
Тесты — это фактически проверка на соответствие требованиям. И если требования к классам легко описываются ассертами, то требования к UI формально описать очень сложно. Отсюда и сложность тестирования.
Работа с базой… модели работы с данными могут быть протестированы с использованием тестовых фикстур данных.
0
То есть тестирование UI слишком сложно — пропускаем… Получается что от TDD плясать уже не получается, как это красиво описано в куче статей, о том как от тестов пишем код…
А от тестовых данных в БД плясать… Ну не знаю. Это получается пиши данные — считывай и проверяй читая все строки и сравнивая все ячейки? Так что ли?
В каких проектах вообще применим TDD? Со сложной логикой? Без сложного UI? Без работы с внешними интерфейсами, включая БД? Потому что иначе размер тестов явно превысит сам код раз в 10.
Это даже взять простейший пример, когда тест пишется для функции имеющий 1 вход, 1 выход: требуется проверить и NULL и "" и маленькую строку и большую и ОЧЕНЬ большую и т.д. А берем пример с запросом к базе данных — а там уже с точки зрения выходных данных пусть даже всего 20 полей и 5 разных комбинаций строк — уже имеем дофига вариантов которые НАДО по логике TDD проверять — а ху-ху не хо-хо — пупок-то не развяжется проверять всякую маловероятную ерунду? Когда же сам код-то писать? Элементарный фильтр из 3 частей в каждой 3 чекбокса уже задолбаешься описывать тестами, да еще и само сравнение с возвращаемыми данными из БД…
А Ajax? А JavaScript с точки зрения того же UI? Боюсь даже представить тест сложносвязанной формы и сколько для этого придется кода писать…
По-моему, надо тщательнее проектировать и аккуратно писать код.
А от тестовых данных в БД плясать… Ну не знаю. Это получается пиши данные — считывай и проверяй читая все строки и сравнивая все ячейки? Так что ли?
В каких проектах вообще применим TDD? Со сложной логикой? Без сложного UI? Без работы с внешними интерфейсами, включая БД? Потому что иначе размер тестов явно превысит сам код раз в 10.
Это даже взять простейший пример, когда тест пишется для функции имеющий 1 вход, 1 выход: требуется проверить и NULL и "" и маленькую строку и большую и ОЧЕНЬ большую и т.д. А берем пример с запросом к базе данных — а там уже с точки зрения выходных данных пусть даже всего 20 полей и 5 разных комбинаций строк — уже имеем дофига вариантов которые НАДО по логике TDD проверять — а ху-ху не хо-хо — пупок-то не развяжется проверять всякую маловероятную ерунду? Когда же сам код-то писать? Элементарный фильтр из 3 частей в каждой 3 чекбокса уже задолбаешься описывать тестами, да еще и само сравнение с возвращаемыми данными из БД…
А Ajax? А JavaScript с точки зрения того же UI? Боюсь даже представить тест сложносвязанной формы и сколько для этого придется кода писать…
По-моему, надо тщательнее проектировать и аккуратно писать код.
0
Нет никакого грида, аджаска и т.п., есть метода в API получить_данные_такие_то, вот его и надо тестировать в первую очередь, т.е. приложение должно быть спроектировано удобнотестируемым, с выделенным высокоуровневым API. А отрисовку в грид проверит тестер — уверен там если и будут, то очень мелкие ошибки.
Все варианты перебирать не надо, ибо не всегда и возможно, нужно основные, а если хочется побольше перебрать, то можно взять нечто типа LectroTest
В базу ничего писать не надо, нужно использовать Mock объекты
Все варианты перебирать не надо, ибо не всегда и возможно, нужно основные, а если хочется побольше перебрать, то можно взять нечто типа LectroTest
В базу ничего писать не надо, нужно использовать Mock объекты
0
Ну вот и как ты будешь «данные_такие_то» проверять? Хоть в DataTable тебе их выдай хоть в чём.
«Все данные проверять не надо» — а как же идея-фикс про 100% покрытие кода тестами? А ВДРУГ мы-то и не догадываемся что тут основное?
В базу писать ничего не надо? А вдруг неправильно запросы написали? Что делать? Неужели руками каждый раз перетестировать?
Короче — что же все-таки дает-то такое тестирование? Тут не тестируй, тут упрости, тут вообще заглушки используй…
«Все данные проверять не надо» — а как же идея-фикс про 100% покрытие кода тестами? А ВДРУГ мы-то и не догадываемся что тут основное?
В базу писать ничего не надо? А вдруг неправильно запросы написали? Что делать? Неужели руками каждый раз перетестировать?
Короче — что же все-таки дает-то такое тестирование? Тут не тестируй, тут упрости, тут вообще заглушки используй…
0
А вы кажется неправильно TDD представляете. Тест не после кода, а ДО него писать надо. Тогда и покрытие будет 100%, и вопросов не возникнет что тестировать (как что? что хочешь написать, то и проверь сначала).
А в базу писать ничего не надо, надо тестировать только методы класса, их внешнее проявление, а не внутреннюю кухню (потому что сегодня там MySQL, а завтра Mongo). Если запрос там внутри «неправильно» написан, а тесты зеленые, то ничего, как говорится, и не трогай :)
А в базу писать ничего не надо, надо тестировать только методы класса, их внешнее проявление, а не внутреннюю кухню (потому что сегодня там MySQL, а завтра Mongo). Если запрос там внутри «неправильно» написан, а тесты зеленые, то ничего, как говорится, и не трогай :)
0
Так и буду проверять — если при заданных условиях вернулся ожидаемый набор данных, то ок, более конкретно можно сказать для более конкретного примера
100% покрытие это идеал, но мы в реальном мире, тесты очень ценны даже если не покрывают 100%, а покрытие со временем улучшится до достаточного уровня, начать нужно с того что кажется основным
Не надо путать модульные тесты и интеграционные тесты, модульные проверяют только модуль в изолированном окружении, а интеграционные работу модулей вместе, в интеграционных можно и в базу писать тестовые данные
Даёт знание что модуль с высокой вероятностью работает по спецификации, и что особенно важно — знание того, что наше очередное изменение не ухудшило работу модуля
100% покрытие это идеал, но мы в реальном мире, тесты очень ценны даже если не покрывают 100%, а покрытие со временем улучшится до достаточного уровня, начать нужно с того что кажется основным
Не надо путать модульные тесты и интеграционные тесты, модульные проверяют только модуль в изолированном окружении, а интеграционные работу модулей вместе, в интеграционных можно и в базу писать тестовые данные
Даёт знание что модуль с высокой вероятностью работает по спецификации, и что особенно важно — знание того, что наше очередное изменение не ухудшило работу модуля
0
Тестировать надо прежде всего BLL (бизнес лоджик лэйер — я правильно понял?). DAL (дата абстракшн лэйер?) и DB уже как бы считаются идеальными и в тестировании не нуждаются (их тестировал их разработчик) — вы априори считаете, что если передали DAL запрос на сохранение объекта, то он сохранится, на загрузку — загрузится.
По идее в BLL у вас запросов быть не должно вообще на этапе разработки, если и появятся, то на этапе оптимизации. Мок объекты это не заглушки, а «проверялки» того, что ваш объект правильно вызывает другие объекты. Допустим у вас есть объект User, который в методе Save вызывает метод Save объекта Storage, передавая ему параметры login и password_hash, которые задаются в конструкторе (хэш считается внутри). В тесте вы создаёте объект User, передав в конструкторе строковые константы логин и пароль. Подставляете вместо Storage объект StorageMock, который конфигурируете так, что он ожидает вызова метода Save c логином и хэшем пароля и вызываете метод Save объекта User. Выполняете тест. Если метод Save объекта StorageMock не будет вызван — тест не пройдёт. Если будет вызван, то параметры не будут равны ожидаемым (например, пароль не захэширован будет) — тест не пройдёт. Он пройдёт только если метод будет вызван с ожидаемыми параметрами, а занчит когда вы вызовите настоящий Storage, эти параметры будут переданы ему.
Вы подставляете вместо Storage объект StorageMock, который предварительно конфигурир
По идее в BLL у вас запросов быть не должно вообще на этапе разработки, если и появятся, то на этапе оптимизации. Мок объекты это не заглушки, а «проверялки» того, что ваш объект правильно вызывает другие объекты. Допустим у вас есть объект User, который в методе Save вызывает метод Save объекта Storage, передавая ему параметры login и password_hash, которые задаются в конструкторе (хэш считается внутри). В тесте вы создаёте объект User, передав в конструкторе строковые константы логин и пароль. Подставляете вместо Storage объект StorageMock, который конфигурируете так, что он ожидает вызова метода Save c логином и хэшем пароля и вызываете метод Save объекта User. Выполняете тест. Если метод Save объекта StorageMock не будет вызван — тест не пройдёт. Если будет вызван, то параметры не будут равны ожидаемым (например, пароль не захэширован будет) — тест не пройдёт. Он пройдёт только если метод будет вызван с ожидаемыми параметрами, а занчит когда вы вызовите настоящий Storage, эти параметры будут переданы ему.
Вы подставляете вместо Storage объект StorageMock, который предварительно конфигурир
0
«Все данные проверять не надо» — а как же идея-фикс про 100% покрытие кода тестами? А ВДРУГ мы-то и не догадываемся что тут основное?
Для этого есть регрессивные тесты. Обнаружили баг, поняли что что-то забыли, тогда и создаём тест на этот случай. А изначально описываются лишь основные варианты.
0
В каких проектах вообще применим TDD? Со сложной логикой? Без сложного UI? Без работы с внешними интерфейсами, включая БД? Потому что иначе размер тестов явно превысит сам код раз в 10.
Это если тестировать всё приложение как «черный ящик». Но юнит-тестируют не всё сразу, а по отдельности, равно как и пишут. Комбинаторику (интеграцию) после этого тестировать можно, но необязательно (нужно для контроля качества, а не для кодинга с TDD).
Ну и да, TDD применим в любых проектах. И чем сложнее проект, тем более необходим. Да, время занимает, но порядка 50%, зато фактически разгружает QA. К тому же необязательно покрывать совсем всё. Можно например только «ядро» и хрупкие участки. Ну а UI покрывать имхо стоит уже в самую последнюю очередь (поскольку меняется чаще всего).
0
А может кто-то написать действительно толковую статью о TDD?
Я вот решил использовать TDD, но пока что никак не могу переделать мозги под написание тестов. Открываю файл для тестов и вступаю в ступор…
С чего начать? Как называть? Что в конце-концов тестить? Ведь можно углубляться до бесконечности в требуемый функционал!
Я вот решил использовать TDD, но пока что никак не могу переделать мозги под написание тестов. Открываю файл для тестов и вступаю в ступор…
С чего начать? Как называть? Что в конце-концов тестить? Ведь можно углубляться до бесконечности в требуемый функционал!
0
Кент Бек. Экстремальное программирование: разработка через тестирование. — «Питер», 2003
Если коротко: перед тем как писать код вы же как-то формулируете требования к нему, вот и пишете эти требования на языке юнит-тест фрэймворка, затем добиваетесь того, чтобы тест запустился (но не прошёл) — формируете пустые классы, объекты, функции и т. п., затем пишете код, чтобы тест прошёл, затем, если нужно, рефакторите код, так, чтобы все тесты не сломались и возвращаетесь к началу цикла — формулировке следующих требований.
Начинать проще всего, имхо, если говорить о вебе и MVC, с модели, тестировать именно бизнес-логику, а не как она сохраняется в БД. Идеально для этого подходит паттерн DataMapper, с ActiveRecord похуже, имхо. Самое сложное по началу выбрать нужный шаг тестирования, когда начинал писать первый проект, используя TDD, то тестировал абсолютно всё, включая среду выполнения, транслятор, сторонние библиотеки (Doctrine в частности :) ).
Если коротко: перед тем как писать код вы же как-то формулируете требования к нему, вот и пишете эти требования на языке юнит-тест фрэймворка, затем добиваетесь того, чтобы тест запустился (но не прошёл) — формируете пустые классы, объекты, функции и т. п., затем пишете код, чтобы тест прошёл, затем, если нужно, рефакторите код, так, чтобы все тесты не сломались и возвращаетесь к началу цикла — формулировке следующих требований.
Начинать проще всего, имхо, если говорить о вебе и MVC, с модели, тестировать именно бизнес-логику, а не как она сохраняется в БД. Идеально для этого подходит паттерн DataMapper, с ActiveRecord похуже, имхо. Самое сложное по началу выбрать нужный шаг тестирования, когда начинал писать первый проект, используя TDD, то тестировал абсолютно всё, включая среду выполнения, транслятор, сторонние библиотеки (Doctrine в частности :) ).
+3
Действительно, может, вам лучше хорошую книжку почитать?
Или может, это поможет habrahabr.ru/blogs/tdd/112851/?
Или может, это поможет habrahabr.ru/blogs/tdd/112851/?
0
Мой рабочий цикл: эксперимент — спецификация — тест — реализация — верификация.
Повторять для каждого бага или новой фичи. Прекрасно подходит для любых динамических языков, но счастливые программисты на Lisp тут однозначно в выигрыше: SLIME прекрасно подходит для экспериментирования.
Повторять для каждого бага или новой фичи. Прекрасно подходит для любых динамических языков, но счастливые программисты на Lisp тут однозначно в выигрыше: SLIME прекрасно подходит для экспериментирования.
-1
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Вдохновение для юнит-тестов