简体   繁体   English

在常规mvc控制器中使用标识的单元测试方法(不是web api控制器)

[英]unit test method that uses identity in regular mvc controller (not web api controller)

I have a method in a regular mvc controller that checks the user's identity to see which page the user should be directed to. 我在常规mvc控制器中有一个方法,它检查用户的身份以查看用户应该指向哪个页面。 However, building a unit test against this method raises an "object reference not set" error as User is always null when the method is run as part of a test. 但是,针对此方法构建单元测试会引发“对象引用未设置”错误,因为当方法作为测试的一部分运行时,User始终为null。

public ActionResult Index()
        {
            if (User.Identity.IsAuthenticated)
            {
                if (User.IsInRole("Administrator"))
                {
                    return RedirectToAction("Console");
                }

                ViewBag.StatusMessage = "You are logged in but do not have sufficient permissions.";
            }
            else
            {
                ViewBag.StatusMessage = "Please log in";
            }

            return View();
        }

I have tried various solutions offered at Writing Unit Test for methods that use User.Identity.Name in ASP.NET Web API . 我已经尝试过在Writing Unit Test中为ASP.NET Web API中使用User.Identity.Name的方法提供的各种解决方案。 These generally use something like the following inside the body of the unit test: 这些通常在单元测试的主体内使用类似下面的内容:

var identity = new GenericIdentity("UserName");
Thread.CurrentPrincipal = new GenericPrincipal(identity, null);
var controller = new FooController(); 

This approach works fine if the Controller is an ApiController - ie a controller for a WebApi project but it does not seem to work for a regular web mvc controller. 如果Controller是ApiController,这种方法可以正常工作 - 即WebApi项目的控制器,但它似乎不适用于常规的Web mvc控制器。 The User object remains null. User对象保持为null。 How to solve? 怎么解决?

This link which you have posted related to WebAPI, and quite understandably it is very easy Unit Test the ApiController and access the User object. 您发布的这个链接与WebAPI有关,可以理解的是单元测试ApiController并访问User对象非常容易。

This is some what different to ASP.NET MVC as you have seen it is not straightforward. 这是与ASP.NET MVC不同的一些,因为您已经看到它并不简单。 If we go down the path where using manual/handwritten mocks, we probably find our selves mocking the entire universe as oppose to write a valuable test. 如果我们走下使用手动/手写模拟的道路,我们可能会发现我们自己嘲笑整个宇宙,反对写一个有价值的测试。

I include the both approaches so you can get the idea. 我包含了这两种方法,因此您可以了解这个想法。 I 'm also use the same example from the link have posted in the question. 我也使用了问题中发布的链接中的相同示例。

Using manual hand written mocks 使用手动手写的模拟

//System Under Test - i.e to test User
public class SutController : Controller
{
    public string Get() {
        return User.Identity.Name;
    }
}

public class TestableControllerContext : ControllerContext {
    public TestableHttpContext TestableHttpContext { get; set; }
}

public class TestableHttpContext : HttpContextBase {
    public override IPrincipal User { get; set; }
}

[TestMethod]
public void IndexNoneMoq()
{
    var identity = new GenericIdentity("tugberk");
    var controller = new SutController();

    var controllerContext = new TestableControllerContext();
    var principal = new GenericPrincipal(identity, null);
    var testableHttpContext = new TestableHttpContext
    {
        User = principal
    };

    controllerContext.HttpContext = testableHttpContext;
    controller.ControllerContext = controllerContext;

    Assert.AreEqual(controller.Get(), identity.Name);
}

Using Mocking/Isolation framework ie Moq 使用Mocking / Isolation框架即Moq

[TestMethod]
public void IndexMoq()
{
    var identity = new GenericIdentity("tugberk");          
    var controller = new SutController();

    var controllerContext = new Mock<ControllerContext>();
    var principal = new Mock<IPrincipal>();
    principal.Setup(p => p.IsInRole("Administrator")).Returns(true);
    principal.SetupGet(x => x.Identity.Name).Returns("tugberk");
    controllerContext.SetupGet(x => x.HttpContext.User).Returns(principal.Object);
    controller.ControllerContext = controllerContext.Object;

    Assert.AreEqual(controller.Get(), identity.Name);
}

Note that I think the next version of ASP.NET uses the same underlying components for both WebAPI and MVC (AFAIK), so this could be a one way Unit testing target controller which uses the User instance. 请注意,我认为下一版本的ASP.NET对WebAPI和MVC(AFAIK)使用相同的底层组件,因此这可能是单向测试使用User实例的目标控制器。

Here is the Manual Mock you can write in MVC Unit test Controller. 这是您可以在MVC单元测试控制器中编写的手动模拟。

[TestMethod]
public void IndexManualMoq()
{
.
.
.
    var controller = new SutController();
    controller.ControllerContext = new ControllerContext
    {
        HttpContext = new MockHttpContext
        {
            User = new GenericPrincipal(new GenericIdentity("JDoe"), null)
        }
    };
.
.
.
}

private class MockHttpContext : HttpContextBase
{
    public override IPrincipal User { get; set; }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM