シナリオ:単体テストの方法を学んでいます。現在、nUnit と FakeItEasy を使用した mvc アクション メソッドのテストに取り組んでいます。存在しない ID が渡された場合にメソッドが例外をスローすることを確認するテストがあります。アクション メソッドは、何も見つからない場合に例外をスローする .Single() のリポジトリ ラッパー メソッドを呼び出します。これはいい。
私のテストでは、次のことを行います。
- FakeItEasy を使用して偽の IRepository を作成する
- テストデータの作成
- テスト データからデータを取得するように .Single() ラッパー メソッドを構成する
問題:これをテストする際に問題があります。問題は、無効な ID が渡されると、アクション メソッド自体ではなく、偽のリポジトリの構成コードで例外がスローされることです。その理由は明らかです。アクションメソッドが実行される前に構成コードが実行され、構成コードはテストデータで .Single() を呼び出します...これには(もちろん意図的に)無効なIDが含まれていません。そのため、その場で例外をスローし、アクション メソッドに到達することさえありません。私がよくわからないのは、これを回避する方法です。アクション メソッド内で例外をスローする必要があります。この難問を回避する方法で戻り値を構成する方法がわかりません。
コード:
コントローラ コード
public ViewResult Details(int id)
{
var dbPart = _repository
.GetSingleRecord<Part>(x => x.PartID == id);
var viewmodel = new DetailsViewModel()
{
PartID = dbPart.PartID
};
return View(viewmodel);
}
テストコード
[TestFixtureSetUp]
public void TestFixtureSetUp()
{
// Create a fake PartID that exists
partID_that_exists = 1;
// Create a fake PartID that doesn't exist
partID_that_doesnt_exist = -100;
}
[Test]
public void an_exception_is_thrown_if_the_part_doesnt_exist()
{
// Arrange
FakeRepository.FakePartID = partID_that_doesnt_exist;
_fakeRepository = FakeRepository.Create();
_controller = new PartController(_fakeRepository);
// Act & Assert
Assert.Throws<InvalidOperationException>(() =>
_controller.Details(partID_that_doesnt_exist));
}
偽のリポジトリ コード
public class FakeRepository
{
public static int? FakePartID { get; set; }
public static IBasicRepository Create()
{
// Create fake repository
var fakeRepository = A.Fake<IBasicRepository>();
// Create fake test data
var fakeParts = new List<Part>()
{
new Part()
{
PartID = 1, PartDesc = "Fake Part 1"
},
new Part()
{
PartID = 2, PartDesc = "Fake Part 2"
}
};
// Configure fake repository to return fake data
A.CallTo(() => fakeRepository.GetAllRecords<Part>())
.Returns(fakeParts);
if (FakePartID.HasValue)
{
/* BELOW CODE IS THE PROBLEM */
A.CallTo(fakeRepository)
.Where(call => call.Method.Name == "GetSingleRecord")
.WithReturnType<Part>()
.Returns(fakeParts.Single(x => x.PartID == FakePartID));
}
// Return the newly created & configured fakeRepository
return fakeRepository;
}
}