2010-06-12 33 views
34

Tôi cần phải tạo Bài kiểm tra Đơn vị cho trang web ASP.NET MVC 2.0. Trang web sử dụng Xác thực Windows.Mocking User.Identity trong ASP.NET MVC

Tôi đã đọc về sự cần thiết giả lập ngữ cảnh HTTP cho mã liên quan đến HttpContext. Tôi cảm thấy như tôi đang bắt đầu có được một xử lý trên mô hình DI là tốt. (Cung cấp cho lớp một thuộc tính của loại IRepository và sau đó vượt qua trong một đối tượng Kho lưu trữ khi bạn khởi tạo bộ điều khiển.)

Điều tôi chưa hiểu là cách thích hợp để Mô phỏng đối tượng Chính của Windows có sẵn thông qua Người dùng. Danh tính. Đây có phải là một phần của HttpContext không?

Có cơ thể nào có liên kết đến bài viết thể hiện điều này (hoặc đề xuất cho sách) không?

Cảm ơn,

Trey Carroll

Trả lời

29

Tôi đã sử dụng IoC để trừu tượng này đi với một số thành công. Lần đầu tiên tôi xác định một lớp đại diện cho người dùng hiện đã đăng nhập:

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; } 
} 

Phải mất IIdentity trong hàm tạo để đặt giá trị của nó. Đối với các bài kiểm tra đơn vị, bạn có thể thêm một hàm tạo khác để cho phép bạn bỏ qua phụ thuộc IIdentity.

Và sau đó tôi sử dụng Ninject (chọn container IoC yêu thích của bạn, không quan trọng), và tạo ra một ràng buộc cho IIdentity như vậy:

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

Sau đó, bên trong bộ điều khiển của tôi Tôi tuyên bố phụ thuộc vào constructor:

CurrentUser _currentUser; 

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

các container IoC thấy rằng HomeController mất một đối tượng CurrentUser, và các nhà xây dựng CurrentUser mất một IIdentity. Nó sẽ tự động giải quyết các phụ thuộc, và thì đấy! Bộ điều khiển của bạn có thể biết ai là người dùng hiện đang đăng nhập. Dường như nó hoạt động khá tốt với tôi với FormsAuthentication. Bạn có thể thích ứng với ví dụ này để xác thực Windows.

+1

Đối với tôi, phương pháp này là thích hợp hơn để chế giễu bộ điều khiển và nguyên tắc và ngữ cảnh http, v.v., mỗi khi tôi quên chính xác phần nào tôi cần giả lập và phải truy tìm các thử nghiệm khác để tìm mã phù hợp để sao chép và dán. Trong trường hợp của tôi, các bộ điều khiển có giao diện ICurrentUserResolver, có một phương thức ResolveCurrentUser(), và bộ điều khiển không bao giờ phải lo lắng về cách người dùng hiện tại được xác định. –

+1

Cảm ơn bạn @ JohnNelson, bạn đã cứu mạng tôi –

1

Tôi đã thay đổi môi trường dev global.asax và Web.Config để sử dụng FormsAuth để buộc một người dùng cụ thể. Tên người dùng sử dụng cùng định dạng WindowsAuth. Xem:

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

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

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

Windows hoặc hình thức Auth cổ phiếu với mẫu đăng nhập cùng.

Ứng dụng sẽ hoạt động với cả xác thực Windows và Xác thực mẫu.

14

Tôi không biết về MVC 2.0, nhưng trong các phiên bản mới hơn, bạn có thể thử các 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 }; 

cũng How to unit-test an MVC controller action which depends on authentification in c#?

5

Ví dụ xem cho chế giễu tên truy cập và SID trên MVC4. Username và SID (Windows Authentication) trong hành động sau đây cần được kiểm tra:

[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(); 
    } 
} 

tôi sử dụng MoqVisual Studio Test Tools. Xét nghiệm này được thực hiện như sau:

[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

Để thử WindowsIdentity bạn có thể làm như sau:

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); 

sau đó sử dụng mockedPrincipal.Object để có được những thực tế WindowsIdentity