我会说你需要限制你正在测试的内容。在业余时间,我正在开发一个以 EF5 作为后端的 MVC4 项目,其中包含存储库和数据服务。我曾尝试模拟 EntityFramework 行为,但它太复杂了。一般来说,这里的人们一致认为模拟数据库上下文是毫无意义的。无论如何,微软都会对此进行测试,所以不要费心测试自己已经被 MS 测试过的东西。
在我的项目中,我为此设置了测试项目和测试数据库。但我不测试存储库,因为它们非常透明且接近 EF。我通过将真实上下文和连接字符串提供给测试数据库来测试我的数据服务。对于每个测试类,我都会删除数据库并重新创建结构。我正在为每个测试重新填充数据,因此测试始终针对相同的数据运行。
这被认为是一个集成测试,因为在这里我要经过几层,然后再点击数据库。在这些测试中,我发现了我在 DB 中的关系和 DbContext 中的其他问题可能遇到的所有问题。
但就我进行集成测试而言 - 我的控制器(和其他对象)使用模拟依赖项进行测试(我使用的是 Moq)。一旦我对 UI 有了更深入的了解,我可能会通过 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);
}
}
并且不要忘记,没有任何自动化测试可以取代真实的人通过系统并单击随机按钮,试图破坏事物。很多时候单元测试缺少来自用户的随机输入。这在机器上是很难模仿的。