Как я могу подтвердить, что Open() был вызван на моем ServiceHost в моем модульном тесте
У меня есть служба Windows, которая открывает две службы WCF. Я хочу выполнить модульный тест OnStart() и утверждать, что service1.Open() и service2.Open() вызывается. OnStart() выглядит так:
protected override void OnStart(string[] args)
{
// host WCF services
_service1.Open();
_service2.Open();
}
Я внедряю сервисы в перегрузку конструктора как таковую:
public WinService(ServiceHostBase service1,
ServiceHostBase service2)
{
_service1 = service1;
_service2 = service2;
InitializeComponent();
}
Я использую RhinoMocks для создания заглушки ServiceHostBase следующим образом:
[TestMethod()]
public void WinServiceOnStartCallsDependenciesAsExpected()
{
ServiceHostBase service1 = MockRepository.GenerateStub<ServiceHostBase>();
ServiceHostBase service2 = MockRepository.GenerateStub<ServiceHostBase>();
WinService target = new WinService(service1, service2);
WinService_Accessor privateTarget = new WinService_Accessor(new PrivateObject(target));
privateTarget.OnStart(null);
Когда мой тест вызывает OnStart(), я получаю исключение нулевой ссылки, когда он вызывает service1.Open(). Я подтвердил, что service1 в данный момент является поддельным объектом и что это Open (), который выбрасывает ноль. Я знаю, что Open () на самом деле является методом для System.ServiceModel.Channels.CommunicationObject, и я также попытался использовать Stubbing или Mocking, но я все еще получаю ошибку ref объекта. Это не виртуальный метод, так что я бы подумал, что он не переопределяется с помощью смоделированной версии, но когда я пытаюсь настроить Ожидание reportservice.Stub(r => r.Open())
, Я получаю другое исключение из-за отсутствия тайм-аута по умолчанию, как если бы он выполнял реальный метод CommunicationObject Open() вместо чего-то RhinoMocky, который выбрасывает нулевую ссылку.
Все это говорит о том, что я просто ищу справку о том, как подтвердить, что Open () вызывается на моем ServiceHost в модульном тесте. знак равно
1 ответ
ServiceHostBase.Open
звонки CommunicationObject.Open
под капотом. Что, как часть его реализации, делает много разных вещей - таких как проверка состояния объекта, создание других объектов, вызов методов, свойств и так далее. И поскольку он не виртуален (ваше предположение было правильным), Rhino вызовет реализацию базового класса.
Чтобы это сработало, вам, вероятно, придётся высмеиватьCommunicationObject
зависимости, и он все еще не будет уверен, добьетесь ли вы успеха или нет (некоторые типы / методы могут быть простонемодными для Rhino, считайте статичными, запечатанными или другими не виртуальными). Вот почему вы должны:
- Оставьте этот вид тестирования интеграционным тестам; тогда у вас будет
.Open
протестировано в среде конечного пользователя - Ввести обертку вокруг
ServiceHostBase
и передать его как зависимость от интерфейса; это требует дополнительной работы (новый интерфейс и простой класс-обёртка), но позволяет вам делать именно то, что вы хотели
Имейте в виду, что добавление оболочки будет только делегировать проблему дальше (классу оболочки ' Open
метод, который по сути будет вызывать ServiceHostBase.Open
- Вы тоже должны это проверить?). С другой стороны, интеграционные тесты могут отлавливать проблемы не так быстро, как модульные тесты (при условии, что вы выполняете их реже). В зависимости от того, насколько критичным вы считаете OnOpen
быть, какой путь вы выбрали, это более или менее суждение.