Edited at

Azure ServiceFabric - ServiceFabric.Mocksを利用したStatefulServiceの単体テスト

More than 1 year has passed since last update.


環境

Visual Studio 2017

Service Fabric SDK 2.6.210

ServiceFabric.Mocks 2.10

SDKとMockのバージョンが異なると実行時エラーとなる場合があります。

MockはSDKのバージョンと合ったものを利用してください。


テスト対象

Azure Service Fabric - Web Apiを実装してみるで実装したデータ更新処理に対してテストを実装する。


HogeStatefulService.cs

public async Task Update(IEnumerable<User> users)

{
var myDictionary = await this.StateManager.GetOrAddAsync<IReliableDictionary<int, User>>(_dictionaryName);

using (ITransaction transaction = this.StateManager.CreateTransaction())
{
foreach (User user in users)
{
await myDictionary.AddOrUpdateAsync(transaction, user.Id, user, (key, value) => user);
}
await transaction.CommitAsync();
}
}



環境の準備


テスト用コンストラクタの追加

StateManagerのMockを利用できるように下記のコンストラクタをテスト対象のStatefulServiceに実装する。


HogeStatefulService.cs

public HogeStatefulService(StatefulServiceContext context, IReliableStateManagerReplica reliableStateManagerReplica)

: base(context, reliableStateManagerReplica)
{}


テストで利用するライブラリの準備

テストプロジェクトを作成し、Moqと ServiceFabric.MocksをNugetから取得

Package Manager Consoleで下記を実行

ServiceFabric.Mocks

PM> Install-Package ServiceFabric.Mocks -Version 2.1.0

GUIでNugetから取得する場合、ServiceFabric.Mocksの"s"まで入力しないとなぜか検索に引っかからないので注意(これだけ完全一致???)


テスト実装


ServiceContextFactoryとStateManagerのMockを作成

    StatefulServiceContext context = MockStatefulServiceContextFactory.Default;

MockReliableStateManager mockStateManager = new MockReliableStateManager();


上記Mockを利用してテスト対象のインスタンスを生成

    HogeStatefulService target = new HogeStatefulService(context, mockStateManager);


初期データを登録(必要な場合)

    IReliableDictionary<int, User> dictionary = await mockStateManager.GetOrAddAsync<IReliableDictionary<int, User>>("MyDictionary");

IEnumerable<User> setupDataSet = new List<User>
{
new User{ Id = 1, FirstName = "太郎", LastName = "山田"},
new User{ Id = 2, FirstName = "花子", LastName = "山田"}
};

using (ITransaction transaction = mockStateManager.CreateTransaction())
{
foreach (var setupData in setupDataSet)
{
await dictionary.AddAsync(transaction, setupData.Id, setupData);
}
await transaction.CommitAsync();
}


テストの実行

    await target.Update(new List<User> { new User { Id = 1, FirstName = "次郎", LastName = "山本" } });


Assert

    using (ITransaction transaction = mockStateManager.CreateTransaction())

{
User result = (await dictionary.TryGetValueAsync(transaction, 1)).Value;

Assert.AreEqual(1, result.Id);
Assert.AreEqual("次郎", result.FirstName);
Assert.AreEqual("山本", result.LastName);
}


テストコード全体

[TestMethod]

public async Task UpdateTest()
{
// setup
StatefulServiceContext context = MockStatefulServiceContextFactory.Default;
MockReliableStateManager mockStateManager = new MockReliableStateManager();

HogeStatefulService target = new HogeStatefulService(context, mockStateManager);
IReliableDictionary<int, User> dictionary = await mockStateManager.GetOrAddAsync<IReliableDictionary<int, User>>("MyDictionary");
IEnumerable<User> setupDataSet = new List<User>
{
new User{ Id = 1, FirstName = "太郎", LastName = "山田"},
new User{ Id = 2, FirstName = "花子", LastName = "山田"}
};

using (ITransaction transaction = mockStateManager.CreateTransaction())
{
foreach (var setupData in setupDataSet)
{
await dictionary.AddAsync(transaction, setupData.Id, setupData);
}
await transaction.CommitAsync();
}

// Act
await target.Update(new List<User> { new User { Id = 1, FirstName = "次郎", LastName = "山本" } });

// Assert
using (ITransaction transaction = mockStateManager.CreateTransaction())
{
User result = (await dictionary.TryGetValueAsync(transaction, 1)).Value;

Assert.AreEqual(1, result.Id);
Assert.AreEqual("次郎", result.FirstName);
Assert.AreEqual("山本", result.LastName);
}
}


まとめ

ServiceFabric.MocksのStateManagerのMockを利用することで、StateManagerのTransaction管理やデータの永続化を利用している部分のテストが可能となる。

参考:GitHub - ServiceFabric.Mocks