Видео. Пример разработки приложения с помощью TDD

18 февраля 2010 г.

В этом видео я разрабатываю приложение с помощью TDD на языке C#. Кроме демонстрации того, как надо писать модульные тесты, я постарался показать, как работает TDD на уровне приложения в целом.

При разработке применил принцип инверсии зависимости, а также использовал IoC-контейнер.

Ссылки:

34 комментария:

  1. Спасибо за видео, очень понравилось, как впрочем и весь другие статьи!

    Вопрос:
    Почему желательно интерфейсы и реализацию размещать в разных сборках?

    И кстати, там небольшая неточность в презентации, на слайде с заголовком "Принцип инверсии зависимости" SimpleReportSender использует IMailer а не IReportsRepository.

    ОтветитьУдалить
  2. @Михаил
    Интерфейсы нужно размещать рядом с тем кодом, который их использует. А реализации интерфейсов отдельно.
    В презентации видно, что предполагалось несколько видов отправителей сообщений: SmsReportSender и SmtpReportSender. Если мы объявим интерфейс и обе его реализации в одном месте, то получиться, что клиенты, которые используют *только* SmsReportSender получат в наследство еще и SmtpReportSender, в котором они абсолютно не нуждаются:) и наоборот.

    Если же мы объявим в разных сборках, то можем поставлять нашим клиентам только необходимые им реализации интерфейсов.

    Подробнее об это можно почитать в книге Роберта Мартина Agile Software Development. В главе 20 принципы упаковки программных проектов.

    ОтветитьУдалить
  3. @Александр
    Опять слишком большими шагами двигался:)

    ОтветитьУдалить
  4. @Михаил

    В добавление к словам Сани хочу дать ссылку http://blog.byndyu.ru/2009/12/blog-post.html#inverted-architecture

    Здесь видно, что сборки фактически общаются с интерфейсами других сборок.

    Об это было написано у Фаулера в книге "Архитектура корпоративных приложений", вот выдержка http://martinfowler.com/eaaCatalog/separatedInterface.html

    "И кстати, там небольшая неточность в презентации..."
    Да, спасибо. Теперь я понимаю откуда берутся забавные кино-ляпы ;)

    ОтветитьУдалить
  5. Не совсем понятна роль IoC. Вы говорите, что не будем хардкодить инициализацию объекта в конструкторе, а затем пишете 3 строки кода для IoC. Это не является хардкодом? Ведь, если что-то необходимо будет изменить, придется править не код в конструкторе, а код выше?...

    ОтветитьУдалить
  6. Хорошее видео. Все здорово.
    Вот только, возможно, про IMailer и IReportRepository - это лишнее, т.к. для людей абсолютно не знакомых с проектированием (или только делающих первые шаги в нем) может быть непонятно что да как. Хотя, бесспорно, их применение абсолютно оправдано )))

    ОтветитьУдалить
  7. @s-stude
    Спасибо за вопрос. Действительно в масштабах такого маленького проекта трудно оценить роль IoC контейнера.

    Но представьте себе, что у вас есть 50-60 объектов типа Reporter и с десяток репозиториев. Они все используются в разных частях проекта. В этом случае будет очень удобно выставить зависимости один раз и в одном месте.

    ОтветитьУдалить
  8. @s-stude типичные IoC контейнеры поддерживают внешнюю конфигурацию, обычно в xml формате.

    ОтветитьУдалить
  9. Спасибо за видео, очень понравилось. Есть пара вопросиков: 1) Что следует выносить в проект бизнес логики, а что в проект домена? 2) Вы говорил об огромном (~1200) количестве тестов в серьезном приложении. Каким образом грамотно их структурировать? Ведь можно создать один класс с десятком тестов. А можно создать десять классов, в каждом по одному тесту.

    ОтветитьУдалить
  10. @Виктор
    "Что следует выносить в проект бизнес логики, а что в проект домена?"
    На этот вопрос довольно трудно дать однозначный ответ. Вообще ответ звучит так: в бизнес логику класс бизнес логики, а в домен классы домена. Что есть что в вашем приложении решать вам. Чтобы лучше ориентироваться в этом вопросе советую прочитать книжку по DDD.

    "Каким образом грамотно их структурировать?"
    На каждую сборку есть сборка модульных тестов. На каждый класс есть тестовый класс. В этом классе все тесты, которые тестируют логику данного класса. Обычно в одном тестового классе около 5-10 тестов.

    ОтветитьУдалить
  11. Большое спасибо за ответы. Книжку по DDD как раз читаю в данное время )), вот и решил посоветоваться с человеком, который уже использует это на практике.

    ОтветитьУдалить
  12. Очень хороший доклад для начинающих. Первая половина - просто песня, оч. хорошо рассказано и оч. подробно. Но вот во второй половине вы слишком быстро рассказали про дальнейшую реализацию. Боюсь что новички не поймут. И IoC у вас получился как то сумбурно, вообще непонятно зачем он в этом проекте.
    Вот еслибы вы вторую половину доклада выдержали в томже ключе, что и первую - цены бы докладу небыло.
    Т.к. я не единственных кто сказал вам об этом, надеюсь в будущем мы увидим доработанный доклад, я буду ждать его с нетерпением.

    ОтветитьУдалить
  13. @Rusted
    Спасибо за совет. Этот я уже дорабатывать не буду, но возможно сделают отдельно про применение IoC контейнера.

    ОтветитьУдалить
  14. Видео супер! Очень понравилось и подтолкнуло использовать принципы TDD.

    ОтветитьУдалить
  15. Спасибо, Александр! Чтобы прочувствовать все в полной мере я скачал ReSharper, xUnit и Ninject и параллельно с Вашим видео повторил все показанные действия. Очень впечатлило. Более того, я раньше как-то недооценивал ReSharper, а теперь не представляю себе жизни без него=)

    Скажите, а почему Вы выбрали NInject в качестве IoC контейнера? Я интересуюсь потому, что сам хочу выбрать для себя оптимальное решение.

    ОтветитьУдалить
  16. @i.lukyanov
    Рад, что понравилось =)

    > Скажите, а почему Вы выбрали NInject в качестве IoC контейнера?
    Я как раз сейчас готовлю видео про IoC-контейнер, там более подробно рассмотрю этот вопрос. Но сейчас заранее могу сказать, что не стоит использовать ни однин IoC-контейнер напрямую. Всегда надо делать над ним свою обертку. А Ninject мы использовали, потому что у него очень простой синтаксис, только и всего =)

    ОтветитьУдалить
  17. Спасибо за видео! Еще раз убеждаюсь, что хороший скринкаст лучше многих, пусть даже хороших, статей.

    Возник вопрос: как быть, если не все классы сборки хочется делать видимыми извне? Только самое необходимое. Как тестировать в таком случае? Или это плохая практика и так делать не стоит?

    ОтветитьУдалить
  18. @Constantin
    Спасибо за вопрос, он довольно актуальный.

    Мы делаем такие классы internal и разрешаем тестовым сборкам видеть эти классы с помощью атрибута InternalsVisibleTo

    ОтветитьУдалить
  19. Я пиши обычные прикладные приложения, в которых архитектура из трёх уровней не подходит. В программах много диалоговых окон и сценариев взаимодействия с пользователем. Пытаюсь облегчить себе работу написанием тестов. Но что то я ни как не могу увидеть выгоды от этого. Количество необходимых тестов быстро набигает за несколько десятков, для них приходится писать очень много кода. Да и как покрыть тестами взаимодействие пользователя с GUI?

    ОтветитьУдалить
  20. @Алексей
    А вы на чем приложения пишите?

    Может вам подойдет http://blog.byndyu.ru/2010/04/ioc-aspnet-mvp-model-view-presenter.html

    ОтветитьУдалить
  21. Цитата: "А вы на чем приложения пишите?
    Может вам подойдет http://blog.byndyu.ru/2010/04/ioc-aspnet-mvp-model-view-presenter.html"

    Не очень. Я просто не понимаю где мне "зацепиться" чтоб дальше самому можно было разбираться.

    ОтветитьУдалить
  22. @Алексей

    Все-таки, на чем вы пишите приложения?

    Что не понятного в моделе MVP?

    ОтветитьУдалить
  23. Случайно нашел ваш блог. Спасибо за ваш труд. Очень кстати. Перечитываю все статьи и комменты.

    ОтветитьУдалить
  24. Отличное видео и отличные статьи. Очень помогли в изучении темы. Спасибо.

    ОтветитьУдалить
  25. Отличный вводный урок, спасибо.

    Вопрос. В данном случае поведение еще несуществующего объекта задавалось через его интерфейс и мок-объект, который эмулировал поведение будущего объекта. Что если у нас есть некий язык, где нет никакой мок-подобной библиотеки и нет ничего похожего на лямбда-конструкции, можно ли будет создавать тесты? Если да, то как в таких случаях тестируется поведение объекта, сначала все же создается реальный объект?

    ОтветитьУдалить
  26. @Sergey
    Moq я использовал только ради удобства. Вы можете взять и создать объект-заглушку вручную. Главное, чтобы он реализовывал нужный интерфейс. Просто Moq позволяет не писать это код.

    ОтветитьУдалить
  27. Александр, скажи, а чем обусловлен твой выбор в пользу xUnit, а не скажем того что входит в VS?

    ОтветитьУдалить
  28. @Ринат Муллаянов

    Лучшее API из всех предлагаемых.

    ОтветитьУдалить
  29. Александр, расскажи, пожалуйста, каким образом ты интегрировал xUnit в MS Unit Testing Framework? В видео у тебя явно не консоль используется для запуска тестов. =)

    ОтветитьУдалить
  30. Александр, объясни в чем разница между BusinessLogic и Domain? Каковы критерии для разделения объектов по разным проектам?

    ОтветитьУдалить
  31. Домен - описание объектов предметной области и их поведение. Например, если вы создаете платформу для блогов, то это скорее всего будут: Пост, Комментарий, Контент, Реакция пользователя и т.п.
    Бизнес-логика, по-другому можно назвать сервисы, туда входят команды и запросы, которые есть в вашем приложении. Команды - изменение состояния системы. Например, добавить новый комментарий. Запросы - выборки данных. Например, взять список комментариев для поста #4.

    ОтветитьУдалить

Моя книга «Антихрупкость в IT»

Как достигать результатов в IT-проектах в условиях неопределённости. Подробнее...