Сохранение сложных тестовых данных

Мы используем шаблон Builder для генерации тестовых данных. Эти доменные объекты имеют отношения между ними. Наши функциональные тесты требуют, чтобы эти объекты были сохранены.

Подумайте об этой модели:

модель предметной области

Если я хочу простой экземпляр CI, сделайте aNew().c().build()

Если я хочу, чтобы это было сохранено, я делаю aNew().c().saveIn(session)

Если я хочу экземпляр C с известным BI сделать aNew().c().with(b).build()

Ну, у тебя есть идея. Моя проблема в том, что если я хочу сохранить C, должен ли он продолжать это B? Или это должно быть сохранено перед рукой? А что, если я хочу разумный B по умолчанию? А что если я хочу сохранить D? Должно ли это сохраняться все А, В, С?

Конечно, реальная система намного сложнее (иногда с круговыми ссылками). Я ищу лучшую практику для сохранения сложных тестовых данных.

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

  • Это не устаревший код, который я пытаюсь проверить
  • Я пытаюсь написать тест покрытия, а не модульный тест (в результате я ничего не буду издеваться)
  • Программное обеспечение, которое я пытаюсь протестировать, работает, если база данных заполнена до некоторой степени (она не использует все сущности).

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

  1. Следите за тем, что было установлено явно при построении объекта.
  2. Предположим, что явно установленные объекты уже сохранены, не сохраняйте их.
  3. Сохраняй все остальное (с их собственным упорством).

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

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

Но когда я пытаюсь сохранить свои тестовые данные, Hibernate не позволит мне сохранить сущность без ее отношений.

Как я могу преодолеть эту проблему?

24.09.2009 12:47:45
6 ОТВЕТОВ
РЕШЕНИЕ

Вам нужно лучше определить свои каскады в домене. Если вы не можете проверить это, как вы ожидаете, что он будет работать в реальном приложении?

Например:

A -> B: Кто владелец этих отношений? Вы хотите добавить B в A или наоборот? Это может быть деталь реализации, где у вас могут быть и B.SetParent (A), и A.Children.Add (B), и где вы устанавливаете родительского B в A в случае A.Children.Add (B) (аналогично другому наоборот). Что произойдет, если вы сделаете:

A a1 = new A();
A a2 = new A();
B b = new B();
a1.Children.Add(b);
b.SetParent(a);

Вы должны решить здесь. Ни одно из решений не является идеальным, поэтому здесь применимы в основном личные предпочтения и согласованность приложений.

Работая с ORM, вы сталкиваетесь с этими проблемами ограничений быстрее, чем с простым SQL (или любым другим источником данных, таким как XML или ваш собственный источник данных), но вам нужно будет рассмотреть проблемы, если вы тоже будете писать простой SQL.

Извините, у меня нет определенного ответа для вас, но мне кажется, что вам нужно учитывать некоторые ограничения, которые (я полагаю) вы еще не сделали.

Лично мне нравится шаблон репозитория при работе с NHibernate в DAL. Я делаю свои репозитории реализованными из IDisposable и позволяю им получать сессию каждый. Таким образом, вы получаете шаблон «Единица работы» в свой дизайн.

Удачи с этим :)

1
30.09.2009 14:13:40

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

Моя проблема в том, что если я хочу сохранить C, должен ли он продолжать это B? Или это должно быть сохранено перед рукой?

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

3
24.09.2009 13:03:33
Представьте, что эти данные уже существуют в БД. И еще один процесс (который я тестирую) читает эти данные. Но иногда B имеет значение, и я хочу сделать его видимым в тесте при создании и сохранении B; но иногда они не актуальны, и я пытаюсь скрыть их за строителями.
nimcap 24.09.2009 13:09:26
Это не имеет смысла для меня. Если данные уже находятся в БД, почему (и чем) вам нужно их сохранить? И что вы подразумеваете под «Я хочу, чтобы это [B] было видно в тесте» ??
sleske 24.09.2009 15:08:57
  • О чем говорят ваши тесты?
  • Похоже, вы тестируете устаревшее приложение?
  • Итак, вы взяли функциональность, уже написанную в вашей кодовой базе, и пытаетесь создать тест покрытия?

Дайте нам еще отзывы, пожалуйста

0
24.09.2009 16:04:00

Я разделил ваши ответы по темам.

Моя проблема в том, что если я хочу сохранить C , должен ли он продолжать это B ? А что если я хочу сохранить D? Должно ли это сохраняться все А, В, С?

Это полностью зависит от ограничений домена, которые вы решите применить. Например, является ли C сущностью, а B - объектом значения? Другими словами, имеет ли С уникальную индивидуальность и собственную жизнь? Идентифицируется ли B главным образом по значению и жизненному циклу, тесно связанному с его родительским C ?

Задание вопросов такого типа должно помочь вам принять решение о том, что продолжать, когда и кем.

Например, если и C, и B являются объектами, разделяющими только отношения, вы можете решить сохранить их независимо, поскольку каждый из них может иметь осмысленную жизнь и собственную идентичность. Если B представляет собой объект значения, вы, вероятно, решили бы, чтобы его родительская сущность C управляла его жизнью, включая создание / поиск / обновление / удаление объекта. Это очень хорошо , может включать в себя C сохраняющиеся B .

Или это должно быть сохранено перед рукой?

Чтобы ответить на это, вам, возможно, придется наметить зависимости вашего объекта. Эти зависимости часто представлены ограничениями внешнего ключа, когда граф объектов сохраняется в СУБД. Если C не может функционировать без ссылки на B , то вы, вероятно, захотите сохранить их обоих внутри транзакции, причем сначала выполняется B для соответствия ограничениям внешнего ключа базы данных. Следуя линию мысли выше, если B был ребенок объект или объект значения C , вы , возможно , даже C ответственность за сохраняющиеся B .

А что, если я хочу разумный B по умолчанию?

Создание экземпляров B может быть делегировано B- Factory. Независимо от того, реализуете ли вы эту фабричную логику как метод класса (не экземпляра), конструктор или выделите ее как свой собственный модуль, не имеет значения. Дело в том , у вас есть одно место , где создание и настройка новых B происходит с. Именно в этом месте будет иметь место конфигурация по умолчанию для вновь созданного объекта.

Отличным ресурсом, охватывающим эти типы вопросов, является Domain-Driven Design Эрика Эванса

1
30.09.2009 14:43:00
Я не мог решить, какой из них принять, другой пришел раньше ... поэтому я прошу прощения, я хочу, чтобы был способ принять несколько ответов
nimcap 5.10.2009 06:19:20

Я не уверен, что понял проблему, которую вы пытаетесь решить очень хорошо, но ... как насчет сериализации всего графа в виде XML с использованием чего-то вроде XStream или буферов протокола Google ?

1
3.10.2009 21:48:36
Буфер протокола Google добавлен как любимый
Arthur Ronald 1.10.2010 20:48:15

Насколько я понимаю, проблема в вашем домене (как вы его нарисовали). Насколько я понимаю, C имеет отношение многие-к-одному к B, и база данных охватывает его с помощью поля внешнего ключа, не допускающего значения NULL. С другой стороны, из кода, о котором идет речь, я мог понять, что в коде нет принудительного применения правила «ровно одно», а член, который ссылается на экземпляр B в экземпляре C, может быть нулевым. Насколько я понимаю, модель предметной области всегда должна быть правильной в коде и во время выполнения, поэтому, если бы это правило было применено в коде (например, путем запроса ссылки B в методе C build ()), у вас не было бы любые проблемы с упорством - вы можете просто все упорствовать.

Другое, гораздо более грязное решение - просто программно отбросить все ограничения БД, которые мешают вашим тестам перед тестом, и восстановить их после. Конечно, это сделало бы БД полностью непригодной для любого другого теста, работающего в parralel, но это может быть решено с помощью целостной БД, такой как SQLite или SQL Server Compact Edition, только для тестов.

0
4.10.2009 22:14:02