Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么我的asp.net mvc控制器不称之为';s基类';在单元测试期间初始化方法?_C#_Asp.net Mvc_Unit Testing_Controller - Fatal编程技术网

C# 为什么我的asp.net mvc控制器不称之为';s基类';在单元测试期间初始化方法?

C# 为什么我的asp.net mvc控制器不称之为';s基类';在单元测试期间初始化方法?,c#,asp.net-mvc,unit-testing,controller,C#,Asp.net Mvc,Unit Testing,Controller,我正在尝试对我的控制器进行单元测试,并使用默认的MVC 3AccountController单元测试作为基础。到目前为止,我的控制器如下所示: public partial class HomeController : MyBaseController { public HomeController(IUnitOfWork unitOfWork) { _unitOfWork = unitOfWork; } public virtual ActionResult Index()

我正在尝试对我的控制器进行单元测试,并使用默认的MVC 3
AccountController
单元测试作为基础。到目前为止,我的控制器如下所示:

public partial class HomeController : MyBaseController
{
    public HomeController(IUnitOfWork unitOfWork) { _unitOfWork = unitOfWork; }

    public virtual ActionResult Index()
    {

        return View();
    }

    public virtual ActionResult About()
    {
        return View();
    }
}
MyBaseController
具有以下代码:

public class MyBaseController : Controller
{
    public MyJobLeadsBaseController()
    {
        CurrentUserId = 0;
    }

    protected override void Initialize(RequestContext requestContext)
    {
        if (MembershipService == null) { MembershipService = new AccountMembershipService(); }
        base.Initialize(requestContext);

        // If the user is logged in, retrieve their login id
        var user = MembershipService.GetUser();
        if (user != null)
            CurrentUserId = (int)user.ProviderUserKey;
    }

    public int CurrentUserId { get; set; }
    public IMembershipService MembershipService { get; set; }

    protected IUnitOfWork _unitOfWork;
}
当我运行实际站点时,一切都正常工作,断点显示
Initialize()
被正确触发。但是,以下单元测试从不运行
Initialize(RequestContext)
方法:

    [TestMethod]
    public void Index_Shows_When_Not_Logged_In()
    {
        // Setup
        HomeController controller = new HomeController(_unitOfWork);
        controller.MembershipService = new MockMembershipService(null);
        SetupController(controller);

        // Act
        ActionResult result = controller.Index();

        // Verify
        Assert.IsNotNull(result, "Index returned a null action result");
        Assert.IsInstanceOfType(result, typeof(ViewResult), "Index did not return a view result");
    }

    protected static void SetupController(Controller controller)
    {
        RequestContext requestContext = new RequestContext(new MockHttpContext(), new RouteData());
        controller.Url = new UrlHelper(requestContext);

        controller.ControllerContext = new ControllerContext
        {
            Controller = controller,
            RequestContext = requestContext
        };
    }
通过此单元测试进行的调试表明,在任何时候都不会调用被重写的
MyBaseController.Initialize()
。这会导致在单元测试中未设置my
CurrentUserId
属性,而是在实时系统上设置的问题

我还需要做什么才能触发调用
Initialize()

在“运行实际站点”的情况下,我怀疑它会调用HomeController的默认构造函数,而HomeController的默认构造函数又会调用基本控制器的相应构造函数

尝试将公共HomeController(IUnitOfWork unitOfWork)的自定义ctor修改为

公共家庭控制器(IUnitOfWork unitOfWork):base()


这将确保每次调用基本控制器的默认ctor时都会调用它。

构造函数不会调用Initialize。IIRC调用initialize的是ExecuteCore方法

以下是来自MVC源代码的代码:

protected virtual void Execute(RequestContext requestContext) {
            if (requestContext == null) {
                throw new ArgumentNullException("requestContext");
            }
            if (requestContext.HttpContext == null) {
                throw new ArgumentException(MvcResources.ControllerBase_CannotExecuteWithNullHttpContext, "requestContext");
            }

            VerifyExecuteCalledOnce();
            Initialize(requestContext);

            using (ScopeStorage.CreateTransientScope()) {
                ExecuteCore();
            }
        }
这基本上是在BeginProcessRequest方法中从MvcHandler调用的

更新:

单元测试中不存在RequestContext,因为您没有通过ASP.NET。如果我没记错的话,你应该嘲笑它

在测试中使用Initialize的另一个问题是成员资格提供程序,我自己没有使用它,但是我猜AccountMembershipService会让您在测试中失败吗?在我看来,这将创建脆弱的测试。如果它必须与服务器联系,它可能也会减慢您的速度,并且可能会使您在CI服务器上失败


依我看,从Init方法的基本情况来看,它不应该存在。想到的最简单的解决方案是使用依赖项注入将CurrentUserId注入控制器。当您通过网站向控制器发出请求时,MVC框架将接收该请求并通过许多不同的步骤运行它。MVC知道它必须调用
Initialize
方法,以便在
MyBaseController
类中找到
Initialize
,并执行它。在这一点上,一切都很好,一切正常

当您在测试代码中创建
HomeController
的新实例时,您只是在创建一个类的新实例。您没有通过MVC请求管道运行该类,并且您的测试框架不知道如何执行
Initialize
方法,因此会出现错误

就个人而言,我希望独立于
初始化
方法来测试
索引
操作。上面的
索引
操作为空,因此我无法确切看到您正在尝试执行的操作,但如果您为登录用户返回一个视图,为匿名用户返回另一个视图,我会执行以下操作:

[TestMethod]
public void Index_Shows_When_Not_Logged_In(){
    HomeController controller = new HomeController(_unitOfWork);
    controller.CurrentUserId=0;

    controller.Index();

    //Check your view rendered in here
}

[TestMethod]
public void Some_Other_View_Shows_When_Logged_In(){
    HomeController controller = new HomeController(_unitOfWork);
    controller.CurrentUserId=12; //Could be any value

    controller.Index();

    //Check your view rendered in here
}
MVC contrib项目()中有一些非常漂亮的测试助手,允许您执行以下操作:

controller.Index().AssertViewRendered();

my
HomeController
中没有默认构造函数。唯一的构造函数是接受
IUnitOfWork
的构造函数。您不能调用
new HomeController()