2010-06-12 44 views
34

我需要爲ASP.NET MVC 2.0網站創建單元測試。該網站使用Windows身份驗證。嘲笑ASP.NET MVC中的User.Identity

我一直在閱讀嘲笑處理HttpContext的代碼的HTTP上下文的必要性。我覺得我也開始處理DI模式。 (給這個類一個IRepository類型的屬性,然後在實例化控制器時傳入一個Repository對象。)

但是,我不明白是通過User模擬Windows Principal對象的正確方法。身份。這是HttpContext的一部分嗎?

有沒有任何機構可以鏈接到一篇文章來證明這一點(或書籍推薦)?

感謝,

崔卡羅爾

回答

29

我使用的IoC抽象送人了一些成功。我首先定義一個類來表示當前登錄的用戶:

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

它需要一個IIdentity在構造以設置其值。對於單元測試,您可以添加另一個構造函數以允許您繞過IIdentity依賴項。

然後我用Ninject(挑自己喜歡的IoC容器,無所謂),並創建了一個約束力的IIdentity這樣:

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

然後,我的控制器裏面,我宣佈在依賴構造:

CurrentUser _currentUser; 

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

控制反轉容器看到該HomeController需要CurrentUser對象,並且CurrentUser構造函數採用IIdentity。它會自動解決依賴關係,瞧!您的控制器可以知道當前登錄的用戶是誰。 FormsAuthentication對我來說似乎很好。您可能可以將此示例適用於Windows身份驗證。

+1

對我來說,這個方法是最好嘲諷控制器和原理以及http上下文等等,每次我都忘記了我需要嘲笑哪些部分,並且必須通過其他測試來尋找合適的代碼來複制和粘貼。在我的情況下,控制器採用ICurrentUserResolver接口,該接口具有ResolveCurrentUser()方法,並且控制器從不需要擔心當前用戶是如何確定的。 – 2014-02-19 06:25:32

+1

謝謝@JohnNelson,你救了我的命 – 2017-08-10 04:32:50

1

我已經改變了開發環境global.asax和Web.Config以使用FormsAuth來強制特定用戶。用戶名使用相同的WindowsAuth格式。請參閱:

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或窗體身份驗證共享相同的登錄模式

該應用程序可以同時使用Windows身份驗證和表單身份驗證。

14

我不知道MVC 2。0,但在新版本中,你可以嘲笑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 }; 

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

5

例子中看到關於MVC4嘲諷的用戶名和SID。 在下面的動作的用戶名和SID(Windows身份驗證)應進行測試:

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

我用MoqVisual Studio Test Tools。該測試的實現如下:

[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

嘲笑WindowsIdentity,你可以做到以下幾點:

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

然後使用mockedPrincipal.Object以獲得實際WindowsIdentity