テストしているものを正確に制限する必要があると思います。余暇には、リポジトリとデータ サービスを使用して、EF5 をバックエンドとして使用する MVC4 プロジェクトに取り組んでいます。EntityFramework の動作をモックしようとしましたが、複雑すぎます。そして一般的に、ここでは、DB コンテキストをモックすることはほとんど無意味であることに同意しました。とにかく、マイクロソフトはそれについてテストを行っているので、MS によって既にテストされているものを自分でテストする必要はありません。
私のプロジェクトでは、テスト プロジェクトとそのためのテスト データベースをセットアップしました。ただし、リポジトリは非常に透過的で EF に近いため、テストしません。実際のコンテキストと接続文字列をテスト DB に提供することで、データ サービスをテストしています。テストクラスごとに、データベースを削除して構造を再作成しています。テストごとにデータを再入力しているため、テストは常に同じデータに対して実行されます。
これは統合テストと見なされます。ここでは、データベースにアクセスする前にいくつかのレイヤーを通過しているためです。これらのテストでは、DB のリレーションシップで発生する可能性のあるすべての問題や、DbContext に関するその他の問題を取り上げています。
しかし、統合テストに関して言えば、私のコントローラー (およびその他のオブジェクト) はモックアップされた依存関係 (私は Moq を使用しています) でテストされています。そして、UI についてもう少し詳しくなったら、Web ページ用の Selenium を使っていくつかのテストを作成する予定です。
私のテストプロジェクトの例を次に示します。
[TestFixture]
class ProjectDataServiceTest
{
private ProjectDataService _projectDataService;
private DatabaseSeeder _seeder;
private SiteContext _context;
[TestFixtureSetUp]
public void FixtureSetUp()
{
_context = new SiteContext(); // connection string is taken from app.config file
_seeder = new DatabaseSeeder(_context);
_seeder.InitialiseDb(); // create database structure
ProjectRepository projectRepository = new ProjectRepository(_context);
_projectDataService = new ProjectDataService(projectRepository);
}
[SetUp]
public void TestSetUp()
{
_seeder.SeedDatabase(); // put some test data from a script
}
[TearDown]
public void TestTearDown()
{
_seeder.RemoveData(); // delete everything from all the tables
}
/**************** Tests are here! ********************/
[Test]
public void CheckDatabaseConnectivity()
{
Assert.Pass();
}
[Test]
public void GetNoProjectsForUser()
{ // should return no project for this user, as nothing is assigned
var user = _seeder.Users[0];
var projects = _projectDataService.GetUserProjects(user);
Assert.IsEmpty(user.UserProjectRoles);
Assert.IsEmpty(projects);
}
[Test]
public void GetAllProjetsForUser()
{
var user = _seeder.Users[2];
var projects = (List<Project>)_projectDataService.GetUserProjects(user);
int count = user.UserProjectRoles.Count;
Assert.AreEqual(count, projects.Count);
Assert.False(projects.Contains(_seeder.Projects[0]));
}
}
コントローラーは、平凡な単体テストの方法でテストされます。
[TestFixture]
class ProjectsControllerTest
{
private ProjectsController _projectController;
private Mock<IProjectDataService> _projectDataService;
private Mock<ICurrentUserService> _currentUserService;
[SetUp]
public void SetUp()
{
MapperConfig.SetMappings();
_projectDataService = new Mock<IProjectDataService>();
_currentUserService = new Mock<ICurrentUserService>();
_currentUserService.Setup(s => s.GetCurrentAppUser()).Returns(new AppUser());
_projectController = new ProjectsController(_projectDataService.Object, _currentUserService.Object);
}
[Test]
public void InstanceOfProjectController()
{
Assert.IsInstanceOf<ProjectsController>(_projectController);
}
[Test]
public void Index()
{
var projects = new List<Project>() { new Project() { Name = "one" }, new Project() { Name = "two" } };
_projectDataService.Setup(s => s.GetUserProjects(It.IsAny<AppUser>())).Returns(projects);
var view = _projectController.Index();
Assert.IsInstanceOf<AutoMapViewResult<List<ProjectViewModel>>>(view);
}
}
また、自動化されたテストは、実際の人がシステムを通過し、ランダムなボタンをクリックして物事を壊そうとすることに取って代わることはできないことを忘れないでください. 多くの場合、単体テストにはユーザーからのランダムな入力がありません。そして、それを機械で真似するのは非常に困難です。