Модульное тестирование и внедрение зависимостей Service Fabric

Я не могу протестировать надежный сервис / актера, просто вызвав его конструктор, а затем протестировав его методы. var testService = new SomeService(); генерирует исключение NullReferenceException. Итак, что я могу сделать с развернутой Службой ..

Я понимаю, что развернутые SF Reliable Services / Actors не являются стандартными классами .NET, и модульное тестирование развернутого S / A может быть странной идеей.

В любом случае теперь я пытаюсь попробовать.

Например. Я только что развернул Службу, а в тесте я создал объект Прокси и добавил элемент во входную очередь Службы. Затем мне нужно утверждать, что количество входных очередей = 1. И это работает, если я только что развернул службу, и никакие другие клиенты / службы / участники не использовали ее входную очередь. Но в следующий раз, когда этот тест будет провален, вот в чем проблема. Мне нужно, чтобы Служба перестала работать с другими потребителями, сбросила очередь и затем протестировала ее. Для этого я могу создать свойство TestMode и некоторые методы, такие как PropareoForTests / TestingCompleted, и вызывать их из тестового клиента до и после тестирования.

Неужели это плохая идея? Может быть, есть какие-то рекомендации по модульному тестированию SF? Спасибо.

ОБНОВЛЕНИЕ:

Изучая пример веб-справочного приложения Service Fabric, я обнаружил эту строку TODO:

/// TODO: Temporary property-injection for an IServiceProxyWrapper until constructor injection is available.

Означает ли это, что SF Services улучшат поддержку DI? А что насчет актеров?


person AsValeO    schedule 15.11.2015    source источник
comment
Внедрение зависимостей конструктора теперь доступно в акторах! Когда вы регистрируете свой тип актера, вы также можете зарегистрировать фабрику, которая на самом деле является просто Func ‹›, где вы создаете свой экземпляр класса Actor, который дает вам контроль над созданием вашего Actor, чтобы вы могли вводить зависимости через него. В сервисах вы уже можете это сделать, посмотрите, как мы это делаем, в примере Party Cluster: github.com/Azure-Samples/   -  person Vaclav Turecek    schedule 03.12.2015
comment
Я написал ответ о внедрении зависимостей с единством: stackoverflow.com/questions/30384780/   -  person Poul K. Sørensen    schedule 09.03.2016
comment
@VaclavTurecek ваша ссылка не работает   -  person Dismissile    schedule 14.06.2016


Ответы (2)


На самом деле вы можете тестировать Reliable Services и Actors так же, как тестируете любой другой класс в .NET! Они особенные только в том, что они используют определенные перехватчики в базовой платформе, но кроме этого вы можете создать экземпляр своей службы или класса актора обычным образом и вызвать на нем методы.

В настоящее время Reliable Services немного легче модульного тестирования, потому что основной перехватчик платформы, State Manager, представляет собой интерфейс, подключаемый через конструктор.

Например, ваш класс обслуживания может выглядеть так:

РЕДАКТИРОВАТЬ: обновлено с помощью API выпуска GA (2.0.135)

class MyService : StatefulService
{
  public MyService (StatefulServiceContext context, IReliableStateManager stateManager)
      :base (context, stateManager)
  {
  }

  public void MyMethod()
  {
    // do stuff..
  }
}

Затем вы можете протестировать свой класс обслуживания следующим образом:

[TestMethod]
public TestMyMethod()
{
  MockReliableStateManager stateManager = new MockReliableStateManager();
  MyService target = new MyService(stateManager);

  target.MyMethod();
  // validate results and all that good stuff
}

У нас есть полный рабочий пример реальных сервисов с множеством тестируемых зависимостей, доступный на GitHub: https://github.com/Azure-Samples/service-fabric-dotnet-management-party-cluster

В этом примере есть макеты IReliableStateManager и IReliableDictionary, которые вы можете использовать в качестве отправной точки для своих собственных модульных тестов.

person Vaclav Turecek    schedule 20.11.2015
comment
Спасибо, Вацлав! Это именно то, что нужно. Взгляните, пожалуйста, на обновление. - person AsValeO; 21.11.2015
comment
В RTM (Actors 2.0.135) свойство Actor.StateManager доступно только для чтения (без protected set). Как мне ввести зависимость диспетчера состояний для моего класса акторов? - person Lars Kemmann; 20.04.2016
comment
А как насчет напоминаний и таймеров для актеров? Я могу сам вызвать метод ReceiveReminderAsync, но мне нужно проверить вызовы, выполняемые в RegisterReminderAsync (защищенный метод на ActorBase). - person Lars Kemmann; 23.04.2016
comment
Похоже, мы все еще не можем издеваться над государственным менеджером, как сказал Ларс. Какие-нибудь решения для этого? Как мы проводим модульное тестирование наших акторов, если мы действительно не можем видеть, что они делают с состоянием? - person Cleverguy25; 28.04.2016
comment
Менеджер состояния актеров сегодня не вводится, но мы работаем над тем, чтобы сделать это так. На данный момент вам придется сделать что-то немного шаткое, например, внедрить свой собственный интерфейс управления состоянием, который обертывает диспетчер состояний. - person Vaclav Turecek; 02.05.2016
comment
@VaclavTurecek: Не могли бы вы привести пример того, как вы могли бы внедрить свой собственный интерфейс управления состоянием, который обертывает диспетчер состояний? - person Matt; 03.05.2016
comment
У меня похожая ситуация, и это решение мне очень помогло. Спасибо за это. У меня есть еще одно условие, когда метод, который я тестирую, вызывает другой микросервис с помощью ServiceProxy. Как издеваться над службой, которую я тестирую, используя в ней метод? - person antar; 03.06.2016
comment
Я использую библиотеку SeviceFabric.Mocks: github.com/loekd/ServiceFabric.Mocks - person Thieme; 20.02.2017
comment
Ваш код больше не будет компилироваться после вашего редактирования. Можете ли вы обновить, чтобы показать, как вы справляетесь с издевательством над StatefulServiceContext? Спасибо - person Taran; 29.04.2017

Чтобы издеваться над менеджером состояний в Reliable Actors, вы можете сделать что-то вроде этого:

<удар>

private readonly IActorStateManager _stateManager;

public MyActor(IActorStateManager stateManager = null)
{
    _stateManager = stateManager ?? this.StateManager;
}

На самом деле StateManager еще не инициализирован. Мы можем получить его, когда будет вызван OnActivateAsync:

private IActorStateManager _stateManager;

// Unit tests can inject mock here.
public MyActor(IActorStateManager stateManager = null)
{
    _stateManager = stateManager;
}

protected override async Task OnActivateAsync()
{
    if (_stateManager == null)
    {
        _stateManager = StateManager;
    }
}

Просто убедитесь, что в остальной части кода всегда используется _stateManager вместо this.StateManager.

person Sander Molenkamp    schedule 26.05.2016