2010-06-12 17 views
34

Necesito crear pruebas unitarias para un sitio web ASP.NET MVC 2.0. El sitio usa Autenticación de Windows.Mocking User.Identity en ASP.NET MVC

He estado leyendo sobre la necesidad de simular el contexto HTTP para el código que trata con el HttpContext. Siento que estoy empezando a manejar el patrón DI también. (Proporcione a la clase un atributo de tipo IRepository y luego pase un objeto Repository al instanciar el controlador.)

Lo que no entiendo, sin embargo, es la forma correcta de simular el objeto principal de Windows disponible a través del usuario. Identidad. ¿Es esto parte del HttpContext?

¿Algún cuerpo tiene un enlace a un artículo que demuestra esto (o una recomendación para un libro)?

Gracias,

Trey Carroll

Respuesta

29

que he usado COI que el extracto esta distancia con cierto éxito. La primera vez que se ha definido una clase para representar el usuario actualmente conectado:

public class CurrentUser 
{ 
    public CurrentUser(IIdentity identity) 
    { 
     IsAuthenticated = identity.IsAuthenticated; 
     DisplayName = identity.Name; 

     var formsIdentity = identity as FormsIdentity; 

     if (formsIdentity != null) 
     { 
      UserID = int.Parse(formsIdentity.Ticket.UserData); 
     } 
    } 

    public string DisplayName { get; private set; } 
    public bool IsAuthenticated { get; private set; } 
    public int UserID { get; private set; } 
} 

Se necesita una IIdentity en el constructor para establecer sus valores. Para las pruebas unitarias, puede agregar otro constructor que le permita eludir la dependencia IIdentity.

Y entonces yo uso Ninject (elija su favorita contenedor IoC, no importa), y creó un enlace para IIdentity como tal:

Bind<IIdentity>().ToMethod(c => HttpContext.Current.User.Identity); 

Luego, en el interior de mi controlador Declaro la dependencia en el constructor:

CurrentUser _currentUser; 

public HomeController(CurrentUser currentUser) 
{ 
    _currentUser = currentUser; 
} 

el contenedor IoC ve que HomeController toma un objeto CurrentUser, y la CurrentUser constructor toma un IIdentity. Resolverá las dependencias automáticamente, y ¡listo! Su controlador puede saber quién es el usuario que actualmente está conectado. Parece funcionar bastante bien para mí con FormsAuthentication. Es posible que pueda adaptar este ejemplo a la Autenticación de Windows.

+1

Para mí, este método es preferible burlándose controladores y principios y contextos http, etc., como cada vez que olvido exactamente qué partes necesito para simular y tengo que buscar otras pruebas para encontrar el código adecuado para copiar y pegar. En mi caso, los controladores toman una interfaz ICurrentUserResolver, que tiene un método ResolveCurrentUser(), y el controlador nunca necesita preocuparse por cómo se determina el usuario actual. –

+1

Gracias @JohnNelson, me salvaste la vida –

10

Scott Hanselman muestra cómo usar IPrincipal y ModelBinder para hacer más fácil probar el controlador burlándose de IPrincipal.

1

He cambiado el entorno dev global.asax y Web.Config para usar FormsAuth para forzar a un usuario específico. El nombre de usuario usa el mismo formato de WindowsAuth. Ver:

public override void Init() 
    { 
     base.Init(); 

     this.PostAuthenticateRequest += 
      new EventHandler(MvcApplication_PostAuthenticateRequest); 
    } 

    void MvcApplication_PostAuthenticateRequest(object sender, EventArgs e) 
    { 
     FormsAuthentication.SetAuthCookie("Domain\\login", true); 
    } 

las ventanas o formularios acciones Auth los mismos patrones de inicio de sesión.

La aplicación funcionará con autenticación de Windows y autenticación de formulario.

14

No sé para MVC 2.0, pero en versiones más recientes se pueden burlarse de la ControllerContext:

// create mock principal 
var mocks = new MockRepository(MockBehavior.Default); 
Mock<IPrincipal> mockPrincipal = mocks.Create<IPrincipal>(); 
mockPrincipal.SetupGet(p => p.Identity.Name).Returns(userName); 
mockPrincipal.Setup(p => p.IsInRole("User")).Returns(true); 

// create mock controller context 
var mockContext = new Mock<ControllerContext>(); 
mockContext.SetupGet(p => p.HttpContext.User).Returns(mockPrincipal.Object); 
mockContext.SetupGet(p => p.HttpContext.Request.IsAuthenticated).Returns(true); 

// create controller 
var controller = new MvcController() { ControllerContext = mock.Object }; 

ver también How to unit-test an MVC controller action which depends on authentification in c#?

5

Ejemplo por burlarse nombre de usuario y el SID en MVC4. El nombre de usuario y SID (autenticación de Windows) de la siguiente acción debe ser probado:

[Authorize] 
public class UserController : Controller 
{ 
    public ActionResult Index() 
    { 
     // get Username 
     ViewBag.Username = User.Identity.Name; 

     // get SID 
     var lIdentity = HttpContext.User.Identity as WindowsIdentity; 
     ViewBag.Sid = lIdentity.User.ToString(); 

     return View(); 
    } 
} 

utilizo Moq y Visual Studio Test Tools. La prueba se lleva a cabo de la siguiente manera:

[TestMethod] 
public void IndexTest() 
{ 
    // Arrange 
    var myController = new UserController(); 
    var contextMock = new Mock<ControllerContext>(); 
    var httpContextMock = new Mock<HttpContextBase>(); 
    var lWindowsIdentity = new WindowsIdentity("Administrator"); 

    httpContextMock.Setup(x => x.User).Returns(new WindowsPrincipal(lWindowsIdentity)); 

    contextMock.Setup(ctx => ctx.HttpContext).Returns(httpContextMock.Object); 
    myController.ControllerContext = contextMock.Object; 

    // Act 
    var lResult = myController.Index() as ViewResult; 

    // Assert 
    Assert.IsTrue(lResult.ViewBag.Username == "Administrator"); 
    Assert.IsTrue(lResult.ViewBag.Sid == "Any SID Pattern"); 
} 
0

burlarse WindowsIdentity se puede hacer lo siguiente:

var mockedPrincipal = new Mock<WindowsPrincipal>(WindowsIdentity.GetCurrent()); 

mockedPrincipal.SetupGet(x => x.Identity.IsAuthenticated).Returns(true); 
mockedPrincipal.SetupGet(x => x.Identity.Name).Returns("Domain\\User1"); 
mockedPrincipal.Setup(x => x.IsInRole("Domain\\Group1")).Returns(true); 
mockedPrincipal.Setup(x => x.IsInRole("Domain\\Group2")).Returns(false); 

a continuación, utilizar mockedPrincipal.Object para obtener el real WindowsIdentity