Подтвердить что ты не робот

TDD, DDD и инкапсуляция

После нескольких лет после неудачной практики, переданной от "архитекторов" на моем месте работы, и думая, что должен быть лучший способ, я недавно читал о TDD и DDD, и я думаю, что принципы и практики будет отлично подходит для сложности программного обеспечения, которое мы пишем.

Однако многие из образцов TDD, которые я видел, вызывают метод на объекте домена, а затем проверяют свойства объекта, чтобы обеспечить корректное выполнение поведения.

С другой стороны, несколько уважаемых людей в отрасли (Грег Янг наиболее заметно с его переговорами о CQRS) выступают за полное инкапсулирование каждого объекта домена, удаляя все "геттеры".

Итак, мой вопрос: как проверить функциональность объекта домена, если ему запрещено получать его состояние?

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

4b9b3361

Ответ 1

То, что вы описываете, - это проверка состояния, в которой вы указываете состояние объекта домена. Там есть ветвь TDD, которая называется проверкой поведения, которая использует объекты Mock.

Проверка поведения позволяет указать, какие методы следует вызывать, и если хотите, какие методы не вызываются.

Посмотрите на эту статью Мартина Фаулера для более подробной информации: Mocks не являются заглушками.

Ответ 2

ОК, этот ответ задерживается на один год, -)

Но если вы хотите протестировать модели CQRS, вы можете делать утверждения на событиях с включенным доменом вместо утверждений в состоянии сущности.

например. если вы хотите проверить, звонит ли он: customer.Rename( "Foo" ) приводит к правильному поведению.

Вместо проверки, если customer.Name равно "foo", вы скорее проверяете, есть ли ожидающее событие CustomerRename со значением "Foo" в вашем ожидающем хранилище событий. (в вашем уроне или в списке событий сущности в зависимости от реализации)

Ответ 3

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

На практике я обнаружил, что BDD во многих случаях является более хрупким, чем просто проверка состояния. Хотя некоторые люди могут призывать к определенной теории, она работает только в том случае, если она работает для вас. Государственное тестирование по-прежнему составляет 90% всех тестируемых модульных тестов, и мы хорошо знаем BDD в нашей команде.

Сделайте то, что лучше всего подходит для вас.

Ответ 4

Несколько вещей.

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

Во-вторых, архитектура OO oldschool пытается сделать программное обеспечение безопасным, используя языковые средства защиты, чтобы предотвратить доступ к ним. Архитектура TDD делает программное обеспечение более надежным, написав тесты, которые проверяют, что на самом деле делает код, уделяя меньше внимания использованию языковых конструкций, чтобы гарантировать, что программа не делает.

Наконец, проверка свойства - это не единственный способ проверить код, как он должен был делать. В книге xUnit Design Patterns описаны другие подходы здесь: http://xunitpatterns.com/Result%20Verification%20Patterns.html

Ответ 5

Я вызываю системные общедоступные методы ввода (т.е. вставляю входные данные в систему), а затем получаю (и утверждаю) вывод системы. Я не тестирую внутреннее состояние системы, а скорее ее общедоступное/видимое поведение: Следует ли проверять внутреннюю реализацию или тестировать публичное поведение?

Ответ 6

То, что вы упомянули, называется государственным тестированием. Там также тестирование поведения. Методы, используемые для этого, - это инжекция зависимостей, инверсия управления и издевка:

Все побочные эффекты вашего класса реализуются как вызовы методов в своих "зависимостях" - то есть объекты, поставляемые снаружи, обычно в конструкторе. Затем в вашем модульном тесте вы создаете поддельный объект вместо реального. Поддельный объект может запомнить, был ли вызван его "определенный метод" и что вы утверждаете в своем тесте.

Существует множество Mocking Framework, которые автоматизируют создание макетных объектов путем динамического создания классов, реализующих данный интерфейс. Наиболее популярными являются Rhino.Mocks и Moq.

Ответ 7

Эй, Джастин, как и ты, я недавно думал о добавлении геттеров к моему доменному объекту только для записи для модульного тестирования, но теперь я убежден, что ошибался. Предполагая, что вы впервые приобрели идею о домене только для записи, тогда, если у вас есть получатели, вы просите о неприятностях. Принцип домена только для записи хотел бы, чтобы вы запускали событие из вашего объекта домена или читали из проекции, которую написал объект вашего домена, или что-то в этом роде. Когда вы открываете геттеры, вы начинаете раскрывать объект "форма", и, как говорит Грег Янг, "объекты домена имеют поведение, а не форму".

Сказав это, я борюсь с тем же вопросом... как вы unit test объект домена только для записи? Вот мой текущий план: я подумываю о том, чтобы мой объект домена запускал событие домена, в котором говорилось: "Эти свойства изменены", а в моем unit test я зарегистрирую его, прежде чем отправить "EditCommand". Проверьте сообщение Udi Dahan в разделе "События домена" здесь, а также см. что Эрик Эванс говорит о событиях в домене.

Ответ 8

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