Как я могу подтвердить, что 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, считайте статичными, запечатанными или другими не виртуальными). Вот почему вы должны:

  1. Оставьте этот вид тестирования интеграционным тестам; тогда у вас будет .Open протестировано в среде конечного пользователя
  2. Ввести обертку вокруг ServiceHostBase и передать его как зависимость от интерфейса; это требует дополнительной работы (новый интерфейс и простой класс-обёртка), но позволяет вам делать именно то, что вы хотели

Имейте в виду, что добавление оболочки будет только делегировать проблему дальше (классу оболочки ' Open метод, который по сути будет вызывать ServiceHostBase.Open - Вы тоже должны это проверить?). С другой стороны, интеграционные тесты могут отлавливать проблемы не так быстро, как модульные тесты (при условии, что вы выполняете их реже). В зависимости от того, насколько критичным вы считаете OnOpen быть, какой путь вы выбрали, это более или менее суждение.

Другие вопросы по тегам