Поскольку у вас есть только 2 человека на домохозяйство, вы можете использовать этот трюк для получения минимального и максимального идентификатора клиента на домохозяйство. Это делается в подзапросе.
SELECT
X.HHID,
C1.FIRST_NAME AS I_FIRST_NAME, C1.LAST_NAME AS I_LAST_NAME,
C2.FIRST_NAME AS II_FIRST_NAME, C2.LAST_NAME AS II_LAST_NAME
FROM
(( SELECT
HHID, Min(CID) AS MinCId, IIf(Max(CID)=Min(CID), Null, Max(CID)) AS MaxCId
FROM HouseHold_Client
GROUP BY HHID
) X
INNER JOIN Client AS C1
ON X.MinCId = C1.CID)
LEFT JOIN Client AS C2
ON X.MaxCId = C2.CID;
Цель выражения IIf()
- вывести максимальный идентификатор клиента только в том случае, если он отличается от минимального идентификатора клиента. Чтобы также вернуть запись, когда MaxCId
равно Null
, требуется LEFT JOIN
на C2
.
Я не присоединился к таблице HouseHold
здесь, так как нам нужна только HHID
из нее, которая также доступна в HouseHold_Client
. Вы также можете присоединиться к нему, если вам нужны другие столбцы из него.
Подзапрос:
( SELECT
HHID, Min(CID) AS MinCId, IIf(Max(CID)=Min(CID), Null, Max(CID)) AS MaxCId
FROM HouseHold_Client
GROUP BY HHID
) X
Подзапросы должны быть заключены в круглые скобки и им должно быть присвоено имя (здесь X
). X
действует как обычная таблица, имеющая столбцы HHID
, MinCId
и MaxCId
в основном запросе. Он сгруппирован по HHID
. Т.е. он возвращает одну строку за HHID
. Min(CID)
возвращает наименьшее CID
и Max(CID)
наибольшее CID
за HHID
.
В случае, когда у вас есть 2 клиента на HHID
, это означает, что Min
и Max
дадут этих 2 клиентов. Если у вас есть только 1 клиент, то и Min
, и Max
вернут одного и того же клиента. Если это так, то IIf
вернет Null
вместо Max(CID)
, чтобы избежать двойного возврата одного и того же клиента.
Используйте контейнер AutoMocking. Существует один записанный для RhinoMocks.
Предположите, что у Вас есть класс с большим количеством зависимостей, введенных через инжекцию конструктора. Вот то, на что это похоже для установки его с RhinoMocks, никаким контейнером AutoMocking:
private MockRepository _mocks;
private BroadcastListViewPresenter _presenter;
private IBroadcastListView _view;
private IAddNewBroadcastEventBroker _addNewBroadcastEventBroker;
private IBroadcastService _broadcastService;
private IChannelService _channelService;
private IDeviceService _deviceService;
private IDialogFactory _dialogFactory;
private IMessageBoxService _messageBoxService;
private ITouchScreenService _touchScreenService;
private IDeviceBroadcastFactory _deviceBroadcastFactory;
private IFileBroadcastFactory _fileBroadcastFactory;
private IBroadcastServiceCallback _broadcastServiceCallback;
private IChannelServiceCallback _channelServiceCallback;
[SetUp]
public void SetUp()
{
_mocks = new MockRepository();
_view = _mocks.DynamicMock<IBroadcastListView>();
_addNewBroadcastEventBroker = _mocks.DynamicMock<IAddNewBroadcastEventBroker>();
_broadcastService = _mocks.DynamicMock<IBroadcastService>();
_channelService = _mocks.DynamicMock<IChannelService>();
_deviceService = _mocks.DynamicMock<IDeviceService>();
_dialogFactory = _mocks.DynamicMock<IDialogFactory>();
_messageBoxService = _mocks.DynamicMock<IMessageBoxService>();
_touchScreenService = _mocks.DynamicMock<ITouchScreenService>();
_deviceBroadcastFactory = _mocks.DynamicMock<IDeviceBroadcastFactory>();
_fileBroadcastFactory = _mocks.DynamicMock<IFileBroadcastFactory>();
_broadcastServiceCallback = _mocks.DynamicMock<IBroadcastServiceCallback>();
_channelServiceCallback = _mocks.DynamicMock<IChannelServiceCallback>();
_presenter = new BroadcastListViewPresenter(
_addNewBroadcastEventBroker,
_broadcastService,
_channelService,
_deviceService,
_dialogFactory,
_messageBoxService,
_touchScreenService,
_deviceBroadcastFactory,
_fileBroadcastFactory,
_broadcastServiceCallback,
_channelServiceCallback);
_presenter.View = _view;
}
Теперь, вот то же самое с контейнером AutoMocking:
private MockRepository _mocks;
private AutoMockingContainer _container;
private BroadcastListViewPresenter _presenter;
private IBroadcastListView _view;
[SetUp]
public void SetUp()
{
_mocks = new MockRepository();
_container = new AutoMockingContainer(_mocks);
_container.Initialize();
_view = _mocks.DynamicMock<IBroadcastListView>();
_presenter = _container.Create<BroadcastListViewPresenter>();
_presenter.View = _view;
}
Легче, да?
Контейнер AutoMocking автоматически создает насмешки для каждой зависимости в конструкторе, и можно получить доступ к ним для тестирования как так:
using (_mocks.Record())
{
_container.Get<IChannelService>().Expect(cs => cs.ChannelIsBroadcasting(channel)).Return(false);
_container.Get<IBroadcastService>().Expect(bs => bs.Start(8));
}
Надежда, которая помогает. Я знаю, что моя жизнь тестирования была сделана намного легче с появлением контейнера AutoMocking.
Вы правы, что это может быть громоздким.
Сторонник насмешки методологии указал бы, что код написан неправильно к тому, чтобы быть с. Таким образом, Вы не должны создавать зависимые объекты в этом методе. Скорее инжекционный API должен иметь функции, которые создают соответствующие объекты.
Что касается копирования 6 различных объектов, это правда. Однако, если бы Вы также были поблочным тестированием те системы, то те объекты должны уже иметь инфраструктуру насмешки, которую можно использовать.
Наконец, используйте платформу насмешки, которая делает часть работы для Вас.
Во-первых, если Вы следуете за TDD, затем Вы не переносите тесты вокруг сложной функции. Вы переносите функцию вокруг своих тестов. На самом деле даже это не правильно. Вы вплетаете свои тесты и функции, пишущий обоим в почти точно то же время, с тестами просто немного перед функциями. См. Три Закона TDD.
Когда Вы следуете этим трем законам и прилежны о рефакторинге, затем Вы никогда не волнуете со "сложной функцией". Скорее Вы волнуете со многими, протестированными, простыми функциями.
Теперь, на Вашей точке. Если у Вас уже есть "сложная функция", и Вы хотите перенести тесты вокруг этого затем, Вы должны:
Если, в конце концов, это, DI является все еще громоздким, то думайте о введении отдельного объекта, который содержит ссылки на все Ваши источники данных. Всегда легче ввести одну вещь, а не многих.
У меня нет Вашего кода, но моя первая реакция состоит в том, что Ваш тест пытается сказать Вам, что Ваш объект имеет слишком много сотрудников. В случаях как это я всегда нахожу, что существует недостающая конструкция там, которая должна быть упакована в высокоуровневую структуру. Используя автонасмешку контейнер просто затыкает рот обратной связи, которую Вы получаете от своих тестов. См. http://www.mockobjects.com/2007/04/test-smell-bloated-constructor.html для более длительного обсуждения.
Конструктор DI не является единственным способом сделать DI. Так как Вы используете C#, если Ваш конструктор не делает никакой значительной работы, Вы могли бы использовать Свойство DI. Это упрощает вещи значительно с точки зрения конструкторов Вашего объекта за счет сложности в Вашей функции. Ваша функция должна проверить на ничтожность любых зависимых свойств и бросить InvalidOperation, если они являются пустыми, прежде чем это начнет работу.
Когда трудно протестировать что-то, это обычно - признак качества кода, что код не является тестируемым (упомянутый в этом подкасте, IIRC). Рекомендация состоит в том, чтобы осуществить рефакторинг код так, чтобы код было легко протестировать. Некоторой эвристикой для решения, как разделить код на классы, является SRP и OCP. Для более конкретных инструкций было бы необходимо видеть рассматриваемый код.
В этом контексте я обычно нахожу утверждения в духе «это указывает на то, что у вашего объекта слишком много зависимостей» или «у вашего объекта слишком много соавторов», чтобы быть довольно ложным заявлением. Конечно, контроллер MVC или форма будут вызывать множество различных сервисов и объектов для выполнения своих обязанностей; в конце концов, он находится на верхнем уровне приложения. Вы можете объединить некоторые из этих зависимостей в объекты более высокого уровня (скажем, ShippingMethodRepository и TransitTimeCalculator объединяются в ShippingRateFinder), но это только так, особенно для этих объектов верхнего уровня, ориентированных на представление. Это еще один объект для насмешки, но вы просто запутали фактические зависимости одним слоем косвенного обращения, а не удалили их.
Один кощунственный совет - сказать, что если вы зависимы, внедряете объект и создаете интерфейс для него, который вряд ли когда-либо изменится (вы действительно собираетесь добавить новый MessageBoxService при изменении кода? Действительно? ), то не беспокойтесь. Эта зависимость является частью ожидаемого поведения объекта, и вы должны просто протестировать их вместе, так как в этом тесте интеграции лежит реальная ценность для бизнеса.
Другой кощунственный совет - я обычно вижу небольшую полезность в модульном тестировании MVC. контроллеры или Windows Forms. Каждый раз, когда я вижу, как кто-то насмехается над HttpContext и проверяет, не был ли установлен cookie, я хочу кричать. Кому какое дело, если AccountController установит куки? Я не. Cookie не имеет ничего общего с обработкой контроллера как черного ящика; Интеграционный тест - это то, что необходимо для тестирования его функциональности (хм, вызов функции PrivilegedArea () завершился неудачно после Login () в интеграционном тесте). Таким образом, вы избежите аннулирования миллиона бесполезных модульных тестов, если формат cookie для входа в систему когда-либо изменится.
Сохраните модульные тесты для объектной модели, сохраните интеграционные тесты для уровня представления и по возможности избегайте фиктивных объектов. Если издеваться над конкретной зависимостью сложно, пришло время проявить прагматичность: просто не делайте модульный тест, вместо этого напишите интеграционный тест и перестаньте тратить свое время.
сохраните интеграционные тесты для уровня представления и, по возможности, избегайте фиктивных объектов. Если издеваться над конкретной зависимостью сложно, пришло время проявить прагматичность: просто не делайте модульный тест, вместо этого напишите интеграционный тест и перестаньте тратить свое время. сохраните интеграционные тесты для уровня представления и, по возможности, избегайте фиктивных объектов. Если издеваться над конкретной зависимостью сложно, пришло время проявить прагматичность: просто не делайте модульный тест, вместо этого напишите интеграционный тест и перестаньте тратить свое время.$('div#someDiv').removeAttr("height");
Метод кнопки «Сохранить» должен содержать только вызовы верхнего уровня для делегирования объектов другим объектам . Эти объекты затем могут быть абстрагированы через интерфейсы. Затем, когда вы тестируете метод кнопки «Сохранить», вы тестируете только взаимодействие с макетированными объектами .
Следующим шагом является написание тестов для этих классов более низкого уровня, но все должно стать проще, поскольку вы тестируете их только изолированно. Если вам нужен сложный код настройки теста, это хороший показатель плохого дизайна (или плохого подхода к тестированию).
Рекомендуемое прочтение: