環境
Visual Studio 2017
Service Fabric SDK 2.6.210
ServiceFabric.Mocks 2.10
SDKとMockのバージョンが異なると実行時エラーとなる場合があります。
MockはSDKのバージョンと合ったものを利用してください。
テスト対象
Azure Service Fabric - Web Apiを実装してみるで実装したデータ更新処理に対してテストを実装する。
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に実装する。
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管理やデータの永続化を利用している部分のテストが可能となる。