2

我们的团队在测试方面非常新。我们是第一次使用 scrum。在第一个 sprint 中,我们在 gui 上有 1 个按钮。按下按钮将导致将文本文件的内容转换为数据库(在新线程/任务中)。gui 将显示任务已启动,并将轮询任务的状态。

我们知道如何使用 TDD 方法对所有内容进行单元测试。但是完成后,我们必须进行集成测试。

我们需要在集成测试中执行什么样的测试?我们是否需要通过测试不同的文件来检查数据库中的所有内容是否正确填写?(IE:关系,存储为 varchar(xxx) 的特定格式等?)

如果是这样:这可能非常复杂,对吧?因为您没有 1 或 2 个输入参数,但您有一个完整的文件(我的意思是文件的内容!!!),它是要测试的变量。然后,您可以为这个一键式按钮进行数百甚至数千次测试。最糟糕的事情:大多数测试(即格式化)已经在单元测试中进行了测试。

互联网上的大多数示例显示更多类似 gui 的测试作为集成测试(或者下面的示例是验收测试?):使用正确的用户名和密码登录 - 输入:名称 + 密码 - 预期输出:重定向到主页

使用不正确的用户名和/或密码登录 - 输入:名称和密码(不正确) - 预期输出:警告(登录失败,用户名或密码不正确)

4

2 回答 2

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 轻松创建上面的测试场景,而您所证明的只是 NH​​ibernate 有效,这不是您的目标。美国不可能告诉您需要测试什么,因为我们不知道您的项目或您想要实现的目标,但您应该对您的应用程序逻辑流程有一些了解,以及您是否看到该流程中连接到数据库或文件系统的任何点或将其他一些外部边界传递给您具有业务逻辑的应用程序,您可能希望在其中放置一个测试场景。

于 2012-09-14T15:54:38.307 回答
0

我会说你需要限制你正在测试的内容。在业余时间,我正在开发一个以 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);
        }
}

并且不要忘记,没有任何自动化测试可以取代真实的人通过系统并单击随机按钮,试图破坏事物。很多时候单元测试缺少来自用户的随机输入。这在机器上是很难模仿的。

于 2012-09-14T16:13:26.733 回答