web-dev-qa-db-ja.com

サービスファブリックユニットテストと依存性注入

コンストラクターを呼び出してからメソッドをテストするだけでは、信頼できるサービス/アクターをテストできません。 var testService = new SomeService();はNullReferenceExceptionをスローします。では、デプロイされたサービスで何ができるでしょうか。

デプロイされたSFReliable Services/Actorsは標準の.NETクラスではなく、デプロイされたS/Aの単体テストは奇妙な考えかもしれないことを理解しています。

とにかく今、私はそれを試してみようとしています。

例えば。サービスをデプロイしたばかりですが、テストでは、Proxyオブジェクトを作成し、サービスの入力キューにアイテムを追加しました。次に、入力キューカウント= 1をアサートする必要があります。サービスをデプロイしたばかりで、他のクライアント/サービス/アクターがその入力キューを使用していない場合に機能します。しかし、次回このテストが失敗するのはそれが問題です。他のコンシューマとの動作を停止し、キューを削除してテストするようにサービスを作成する必要があります。この目的のために、いくつかのTestModeプロパティとPropareoForTests/TestingCompletedのようないくつかのメソッドを作成し、テストの前後にテストクライアントからそれらを呼び出すことができます。

これはそのようにするのは悪い考えですか?たぶん、SFのユニットテストに関するガイドラインはありますか?ありがとう。

更新:

調査中に Service Fabric Webリファレンスアプリケーションの例 このTODO文字列を見つけました:

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

SFサービスがDIサポートを改善するということですか?俳優はどうですか?

17
AsValeO

実際には、.NETの他のクラスをテストするのと同じ方法で、信頼できるサービスとアクターをテストできます。これらは、基盤となるプラットフォームへの特定のフックを使用するという点でのみ特別ですが、それ以外は、サービスまたはアクタークラスを通常どおりインスタンス化し、その上でメソッドを呼び出すことができます。

現在、Reliable Servicesは、プラットフォームへのプライマリフックであるState Managerがコンストラクターを介してプラグイン可能なインターフェイスであるため、単体テストが少し簡単です。

たとえば、サービスクラスは次のようになります。

編集:GAリリースAPI(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モックも含まれています。

19
Vaclav Turecek

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を使用してください。

4