单元测试现有的ASP.NET MVC控制器 - c#

我已经阅读了有关单元测试的越来越多的内容,并决心将其投入工作。我用存储库模式,依赖项注入和EF挖出了一个用ASP.NET MVC编写的项目。我的第一个任务是对控制器进行单元测试。这是控制器要测试的代码段:

 IUserRepository _userRepository;
    IAttachmentRepository _attachmentRepository;
    IPeopleRepository _peopleRepository;
    ICountryRepository _countryRepository;

    public UserController(IUserRepository userRepo, IAttachmentRepository attachRepo, IPeopleRepository peopleRepo, ICountryRepository countryRepo)
    {
        _userRepository = userRepo;
        _attachmentRepository = attachRepo;
        _peopleRepository = peopleRepo;
        _countryRepository = countryRepo;
    }

    public ActionResult Details()
    {
        UserDetailsModel model = new UserDetailsModel();

        foreach (var doc in _attachmentRepository.GetPersonAttachments(Globals.UserID))
        {
            DocumentItemModel item = new DocumentItemModel();
            item.AttachmentID = doc.ID;
            item.DocumentIcon = AttachmentHelper.GetIconFromFileName(doc.StoragePath);
            item.DocumentName = doc.DocumentName;
            item.UploadedBy = string.Format("{0} {1}", doc.Forename, doc.Surname);
            item.Version = doc.VersionID;

            model.Documents.Add(item);
        }

        var person = _peopleRepository.GetPerson();
        var address = _peopleRepository.GetAddress();

        model.PersonModel.DateOfBirth = person.DateOfBirth;
        model.PersonModel.Forename = person.Forename;
        model.PersonModel.Surname = person.Surname;
        model.PersonModel.Title = person.Title;

        model.AddressModel.AddressLine1 = address.AddressLine1;
        model.AddressModel.AddressLine2 = address.AddressLine2;
        model.AddressModel.City = address.City;
        model.AddressModel.County = address.County;
        model.AddressModel.Postcode = address.Postcode;
        model.AddressModel.Telephone = address.Telephone;

        model.DocumentModel.EntityType = 1;
        model.DocumentModel.ID = Globals.UserID;
        model.DocumentModel.NewFile = true;

        var countries = _countryRepository.GetCountries();

        model.AddressModel.Countries = countries.ToSelectListItem(1, c => c.ID, c => c.CountryName, c => c.CountryName, c => c.ID.ToString());

        return View(model);
    }

我想测试Details方法并具有以下查询:

1)Globals.UserID属性从会话对象中检索当前用户。我如何轻松地对此进行测试(我正在使用内置的VS2010单元测试和Moq)

2)我在这里调用AttachmentHelper.GetIconFromFileName(),它只是查看文件的扩展名并显示一个图标。我还将在附件存储库中调用GetPersonAttachments,调用GetPerson,GetAddress和GetCountries,以及调用所创建的扩展方法,以将List转换为SelectListItem的IEnumerable。

该控制器动作是不良做法的一个例子吗?它使用了大量的存储库以及其他辅助方法。据我所知,对单个动作进行单元测试将需要大量的代码。这适得其反吗?

在测试项目中对一个简单的控制器进行单元测试是一回事,但是当您进入这样的现实生活中的代码时,它可能会变成怪物。

我想我的问题确实是我应该重构代码以使其更易于测试,还是为了满足当前代码而使测试变得更加复杂?

参考方案

复杂的测试与复杂的代码一样糟糕:它们很容易出现错误。因此,为了使测试简单,通常最好重构应用程序代码以使其易于测试。例如,您应该将映射代码从Details()方法中拉出到单独的帮助器方法中。然后,您可以非常轻松地测试这些方法,而不必担心测试Details()的所有疯狂组合。

我已经拉出下面的人员和地址映射部分,但是您可以将其拉得更大一些。我只是想让您了解我的意思。

    public ActionResult Details() {
        UserDetailsModel model = new UserDetailsModel();

        foreach( var doc in _attachmentRepository.GetPersonAttachments( Globals.UserID ) ) {
            DocumentItemModel item = new DocumentItemModel();
            item.AttachmentID = doc.ID;
            item.DocumentIcon = AttachmentHelper.GetIconFromFileName( doc.StoragePath );
            item.DocumentName = doc.DocumentName;
            item.UploadedBy = string.Format( "{0} {1}", doc.Forename, doc.Surname );
            item.Version = doc.VersionID;

            model.Documents.Add( item );
        }

        var person = _peopleRepository.GetPerson();
        var address = _peopleRepository.GetAddress();

        MapPersonToModel( model, person );

        MapAddressToModel( model, address );

        model.DocumentModel.EntityType = 1;
        model.DocumentModel.ID = Globals.UserID;
        model.DocumentModel.NewFile = true;

        var countries = _countryRepository.GetCountries();

        model.AddressModel.Countries = countries.ToSelectListItem( 1, c => c.ID, c => c.CountryName, c => c.CountryName, c => c.ID.ToString() );

        return View( model );
    }

    public void MapAddressToModel( UserDetailsModel model, Address address ) {
        model.AddressModel.AddressLine1 = address.AddressLine1;
        model.AddressModel.AddressLine2 = address.AddressLine2;
        model.AddressModel.City = address.City;
        model.AddressModel.County = address.County;
        model.AddressModel.Postcode = address.Postcode;
        model.AddressModel.Telephone = address.Telephone;
    }

    public void MapPersonToModel( UserDetailsModel model, Person person ) {
        model.PersonModel.DateOfBirth = person.DateOfBirth;
        model.PersonModel.Forename = person.Forename;
        model.PersonModel.Surname = person.Surname;
        model.PersonModel.Title = person.Title;
    }

ddl在服务器中未更新-asp.net - javascript

我在ASP.NET c#上工作。我有一个DropDownList。 (runat =“ server”)在$ {document).ready上,我更新了它的值:$(document).ready(function () { document.getElementById("ddl").value = "abc"; ……

在ASP.NET MVC中创建数据库回调的最有效方法 - c#

我有一个ASP.NET MVC网页,该网页基本上通过日期过滤器显示MS SQL数据库中表的行。当新行插入数据库表时,我想用新行列表更新网页视图。实现此目标的最有效方法是什么?基本上,我想从我的JavaScript创建一个到数据库服务器的回调,以用新结果更新UI。假设数据库表中的行数很大。(〜1百万)谢谢,cas 参考方案 如果数据库更新非常频繁,则可以按特定…

如何使用JavaScript访问嵌入式ASP.NET GlobalResources? - javascript

我正在开发一个遗留的ASP.NET项目,该项目正试图缓慢地进行调整,但是如果没有像巧克力手指屋一样塌陷的情况,我将无法进行重大更改。我试图为此找到解决方案,但由于术语的特定混合(“ javascript”,“ embedded”和/或“ resource”只是为我提供了有关如何嵌入.js文件的信息,而失败了)。 。),这可能是一种怪异的处理方式。该项目将Ap…

如何使用ASP.NET ViewState使用JavaScript - c#

我的页面中有UL,它为空。我开始使用JavaScript使用LI填充它。在回发阶段如何在asp.net中使用此新添加的动态数据?那是因为我的提交按钮是asp.net控件。我不想使用JS POST。谢谢 参考方案 我过去通过在隐藏字段中填充要发布的动态数据来完成此类操作,您可以-在回传之前触发JavaScript事件,该事件将数据从UL解析到隐藏字段中要么更新…

如何从.Net DLL获取公共出口列表? - c#

我可以使用“ dumpbin”和“ dll export”之类的工具来查看标准win32 DLL的公共入口点(“ exports”),例如Windows \ SYSTEM32 \ GDI32.dll。但是,当我在.Net DLL上使用这些相同的工具时,我看到的仅仅是 2000 .reloc 2000 .rsrc 48000 .text 我有一个C#/。Net…