我们的团队在测试方面非常新颖。我们第一次使用scrum。 在第一个冲刺中,我们在gui上有一个按钮。按下按钮将导致将文本文件的内容转换为数据库(在新线程/任务中)。 gui将显示任务已启动并将轮询任务的状态。
我们知道如何使用TDD方法对所有内容进行单元测试。但是一旦完成,我们必须进行集成测试。
在集成测试中需要执行哪些测试? 我们是否需要通过测试不同的文件来检查数据库中的所有内容是否正确填充? (IE:关系,存储为varchar(xxx)的特定格式等?)
如果是这样:这可能相当复杂吧?因为你没有1或2个输入参数,但你有一个完整的文件(文件的内容,我的意思是!!!),这是可变的测试。然后,您可以为这一个按钮按下数百或数千个测试。最糟糕的事情:大多数测试(即格式化)已经在单元测试中进行了测试。
互联网上的大多数例子都显示出更像gui的测试作为集成测试(或者是接受测试下的示例?): 使用正确的用户名和密码登录 - 输入:名称+密码 - 预期输出:重定向到主页
使用错误的用户名和/或密码登录 - 输入:名称和密码(不正确) - 预期输出:警告(登录失败,用户名或密码不正确)
答案 0 :(得分:2)
您的问题涵盖了许多尝试转向更好的测试和环境建设程序的领域。所以首先让我们来谈谈集成测试。
对于集成测试,您希望大多数情况下都需要一个空数据库,因为您正在测试给定一组特定数据,您可以查询该数据并获得所需结果。
让我们使用像UserFinder类这样的简单示例,您希望能够在系统中找到具有给定名称的用户并获得可用的模型。
public class UserFinder
{
private SomeDbContext _dbContext;
public UserFinder(SomeDbContext dbContext)
{ _dbContext = dbContext }
public User FindUser(string name)
{ _dbContext.Find<User>(new FindUserByNameQuery(_dbContext, name)); }
}
现在在上面虽然它是一个非常垃圾的类,我们可以测试给定数据库中名为“Tester”的用户,当你调用FindUser(“Tester”)时,你应该回到那个用户模型。
因此,作为此测试的一部分,您需要首先在数据库中设置预期用户,然后创建用户查找器,为其提供真正的数据库连接,然后您将查询名为“Tester”的数据库,证明你得到了那个模型。
通过这种方式,您可以在任何上下文中运行该测试,无论是IDE还是构建脚本或命令行,您将获得一致的结果,因为您的测试是自包含的,它会设置场景,运行测试并验证验收标准。然后,一旦完成测试,就应该删除所有数据,重点是您只设置了给定测试所需的内容,并且通常只在该测试中进行设置。
现在理想情况下,集成测试和验收测试比单元测试运行起来要慢得多,你只想测试单元测试中未涉及的内容,但同时你要确保只测试你的逻辑就像你可以使用NHibernate轻松创建上面的测试场景一样,你所能证明的是NHibernate的工作原理,这不是你的目标。 US 不可能告诉你你需要测试什么,因为我们不知道你的项目或你想要实现的目标,但是你应该知道你的应用程序逻辑流程,如果您在该流程中看到连接到数据库或文件系统的任何点,或者将其他外部边界传递给您具有业务逻辑的应用程序,则可能需要将测试方案放入。
答案 1 :(得分:0)
我想说你需要限制你正在测试的是什么。在我的业余时间,我正在开发一个MVC4项目,EF5作为后端,具有存储库和数据服务。我曾尝试模拟EntityFramework行为,但它太复杂了。一般来说,人们一致认为模拟数据库上下文是毫无意义的。微软无论如何都会对此进行测试,所以不要费心去测试MS已经测试过的内容。
在我的项目中,我已经为此设置了测试项目和测试数据库。但我不测试存储库,因为它们非常透明并且接近EF。我正在通过向测试数据库提供真实的上下文和连接字符串来测试我的数据服务。 对于每个测试类,我正在删除数据库并重新创建结构。我正在为每个测试重新填充数据,因此测试始终针对相同的数据运行。
这被认为是一个集成测试,因为在我点击数据库之前,我将经历几个层次。在那些测试中,我正在解决我在数据库中的关系以及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);
}
}
不要忘记,没有自动化测试可以取代真人通过系统并点击随机按钮,试图破解。很多时候单元测试缺乏用户的随机输入。这很难在机器上模仿。