Pull to refresh

Comments 39

Толку от такого теста, если он не работает с реальной базой? Имхо, неправильный у вас подход к тестированию.
Дело в том, что это модульный тест. Его цель — проверка бизнес-логики.
Мне кажется, его цель — проверка бизнес-логики на конкретной модели данных. Разве не так? Или почему не так?
Да, на моделе данных, но без их выборки из базы данных. От этого будет зависить эффективность теста. Более подробно я написал здесь blog.byndyu.ru/2009/04/blog-post.html

Я согласен, что надо тестировать также и с взаимодействием с базой данных, но это уже интеграционные тесты.
Тогда спасибо за пищу для размышлений.
Кстати, особенно интересно было смотреть про «принцип инверсии зависимости»
Модульные тесты — это целый мир. Если ты с ними еще не сталкивался, то откроешь для себя много интересного. Советую изучать в купе с TDD.
Возможно, я не сильно углублялся в терминологию по тестированию. Судя по всему, я пишу интеграционные тесты.
А TDD вещь клёвая, но на практике всё никак не получается писать сначала тесты, потом проект.
Интересно в чем проблема? Можете мне на почту написать? Обсудим.
Проблема (главная), — что менеджмент нашей компании старается всё время ускорить процесс написания приложения. Что приводит даже к тому, что тесты можем и не писать вовсе.
Пожалуй, это единственная причина…
Да, еще опыта такого не было, вот вторая проблема )
Вот вторая проблема — главная. TDD — такая вещь, преимущества которой обязательно должно понимать именно руководство.

Ровно как и то, что TDD — дисциплина, дающая отличный результат _на дистанции_. То есть, может быть «срочный кусок кода» вы до завтра и не напишете, но целое приложение будет написано быстрее (благодаря отсутствию необходимости проводить часы с дебаггером) и будет в разы проще поддерживаться.
Честно говоря все рассказы о TDD и тестировании- это хорошо. Звучит красиво. Даже не плохо получается на тестовых примерах. Но есть хорошая фраза:

«Реальность- это жестокое убийство прекрасной теории, бандой мерзких фактов.»

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

Может это только у меня такое чумное руководство, но думаю я не один такой.
Сочувствую.

На счет того, чтобы тесты не пришлось перелопачивать есть хорошая книга www.amazon.com/xUnit-Test-Patterns-Refactoring-Code/dp/0131495054

Большое кол-во тестов действительно может стать массой, которую сложно поддерживать. Для написания хороших тестов, которые помогают, а не отягощают, надо набить руку и… шишки.
Тесты не должны быть обременяющими — если они таковы, то TDD ведется неправильно. Наборы тестов поддерживать значительно проще, чем многостраничные толмуды ТЗ.

«Весь код перелопатить» — тут проблема отнюдь не в тестах, а в архитектуре. Если она правильно выстроена, то один модуль (unit) вообще должен работать независимо от другого. А тесты в каждый момент времени показывают, где изменения в одном модуле затронули работу другого.

В общем, народ приводит массу доводов, чтобы НЕ использовать TDD, но тут, как говорится, не попробуешь — не почувствуешь. Недаром Google, Microsoft, 37 Signals и прочие немалоизвестные компании используют эти подходы.
«Реальность- это жестокое убийство прекрасной теории, бандой мерзких фактов.»

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

А теперь ситуация:
Пришел утром. Задача: класс должен принимать из бд то-то и то-то. высчитывать следующее. Отдавать туда сразу же.
К обеду сделал.
Пришел после обеда. Задача: класс должен наследовать от вот этого объекта, и реализовывать вот такой функционал. Данные берутся из экселя, высчитываются совсем другие метрики. А затем держатся внутри объекта, пока не потребуется забрать от туда.

В общем хорошо, когда все по шаблону, по книжке. Жаль что мы не в книжке…
Во всем есть свои нюансы, в том числе в тестировании.
Сам процесс разработки должен быть выстроен немного по-другому (на мой взгляд, более организованно).

Например.
«Задача: класс должен принимать из бд то-то и то-то. высчитывать следующее. Отдавать туда сразу же.»

1. Принимать из БД — это уже не бизнес-логика, а инфраструктура. Запись/чтение из БД — отдельная задача, не имеющая прямого отношения к работе бизнес-правила в коде. Если стоит задача проверить прецеденты взаимодействия с реальной БД — необходимы интеграционные тесты.

2. «Высчитывать следующее» — вот это собственно бизнес-логика. Она тестируется отдельно, вообще вне контекста «БД».

3. «Отдавать туда сразу же» — что куда отдавать? После написания и проверки кода на машине разработчика, код должен поступить в центральный репозиторий контроля версий (или его ветку) на сервере, где по определенным условиям запущена общая сборка и необходимый набор общих тестов (Постоянная интеграция a.k.a. Continuous Integration, CI). Это дает гарантию, что все (даже небольшие) изменения полностью «уживаются» со всем проектом.

4. «Задача: класс должен наследовать от вот этого объекта, и реализовывать вот такой функционал.»
Берется актуальный «снимок» нужной части проекта из репозитория. Пишутся тесты для новых бизнес-правил. Вносятся новые элементы бизнес-логики (для которых и писались тесты).

5. «Данные берутся из экселя, высчитываются совсем другие метрики.»
Неважно откуда берутся данные. Связь и работа с источником данных — это инфраструктура и здесь применяется интеграционное тестирование. А вот подсчет тех или иных метрик — бизнес-логика. Она тестируется независимо от источника данных (так как у нас задача проверить механизм, логику, а связь с источником данных мы, как уже было сказано, проверяем с помощью интеграционных тестов).

6. «А затем держатся внутри объекта, пока не потребуется забрать от туда.»
Это все уже бизнес-логика (логика работы объектов предметной области a.k.a. Domain Objects) и тестируется соответственно (unit-тестами вне зависимости от источников данных).

Все автоматизировано, на все есть определенные процедуры, как действовать в том или ином случае. TDD — это не шаблон, это просто другой метод, как раз-таки призванный добавить (а не убавить) гибкости процессу разработки.
Ах, да…

P.S. Руководство — это всегда проблема, думаю в 90% случаев это причина даже не пытаться пробовать новые методики.
Но как то ведь код тестируется? Например, функцией main или через UI? Так почему же эту логику не загнать в тест?
Такое экстремальное программирование в прямом смысле этого слова не должно быть нормальным рабочим процессом. Обычно новая срочная задача вечером в пятницу — признак кривого менеджерства и сигнал о необходимости искать новое место.
Его цель — проверка бизнес-правила, проверка того, что это правило верно описано в коде, а не того, как это физически взаимодействует с базой. Откуда берутся данные с точки зрения работы правила не имеет значения.
«его цель — проверка бизнес-логики на конкретной модели данных»

Все правильно. И ключевой момент в том, что Модель данных (Domain Model) != База данных.
Интересно, как (в каком месте, какими средствами языка, в какой момент) происходит разрешение зависимостей?
В разных библиотеках по-разному. В любом случае у всех IoC-контейнеров открытый исходный код, можно все подробно изучать.
Блин. Неужели всё настолько плохо… Но после прочтения заголовка моё сознание ожидало увидеть в тексте кейворды: «алкоголь, курение, вещества»
Забавно. Добавил два волшебных слова в заголовок.
А я просто хочу сказать спасибо за пост и вообще за труд. Намного лучше, чем читать в википедии :)
Пожалуйста. Главное, чтобы на пользу.
Как то наткнулся на ваш блог, доступно пишете. Спасибо за статью
Я не знаком с C#, поэтому у меня следующий вопрос: правильно ли я понимаю что в C# можно на лету (в runtime) создавать Mock-объекты вокруг интерфейса? То есть нет нужды создавать Mock-объекты классическим способом — фейковой реализацией интерфейса? Например в Actionscript 3 на лету создать нельзя в связи с ограничением возможностей языка.
И еще такой вопрос… Представим ситуацию когда в системе (приложении) есть интерфейс IProduct, и в этой же системе есть много ( > 1 ) реализаций этого интерфейса. Как разруливать ситуацию когда в разных местах должна ижектитится разная реализация интерфейса IProduct?

ЗЫ. Спасибо за отличный скринкаст, очень эффективно, по сравнению с чтением и пониманием данной информации.
Для создания mock-объектов я использовать библиотеку Moq code.google.com/p/moq
Она дает не создавать stub-объекты (class StupProductRepository: IProductRepository), а оборачивать их new Mock(). Это удобно тем, что нет лишнего кода для создания stub-объектов и возможно задавать поведение mockRepository.Setup(r => r.GetLastProduct()).Returns(new Product())

Как разруливать ситуацию когда в разных местах должна ижектитится разная реализация интерфейса IProduct?

Для этого практически во всех IoC-контейнерах предусмотрена условная логика. Например, для Ninject wiki.github.com/enkari/ninject/conventions-based-binding
Александр, спасибо! Отличный скринкаст, равно как и про TDD.

Практически всё из изложенного знал и понимал раньше, но — почти не использовал. Так что для меня подобные скринкасты являются скорее мотивационными, чем информационными. И это прекрасно! Прочитать про best practices — это одно, а посмотреть код, сопровождаемый живыми комментариями — куда нагляднее!
Так что для меня подобные скринкасты являются скорее мотивационными

Это моя главная цель. Рад, что на пользу.
А исходный код откуда можно скачать?
Sign up to leave a comment.

Articles