2012-02-05 71 views
8

我想測試我的AccountController。問題是,在註冊方法我用下一行創建用戶:如何在使用Membership時測試ASP.NET MVC 3身份驗證

Membership.CreateUser(model.Email, model.Password, model.Email, null, null, true, null, out createStatus); 

在Web應用程序,我用一個CustomMembershipProvider,我設置使用的web.config。在我的單元測試會員課程標準SqlMembershipProvider。而不是我在我的應用程序中使用的CustomMembershipProvider

如何設置單元測試環境中的成員資格?我的意思是以編程方式將其設置爲asp網絡在讀取web.config文件後設置它。

我已經使用接口來模擬用戶管理數據層,但我在想這種情況下是否有避免接口的方法。能夠在單元測試中建立模擬的成員資格實施。

public void RegisterTest() 
{ 
    IUsersManager repository = new Tests.Data.UsersManager(); 
    AccountController target = new AccountController(repository); 
    //be able to set Membership underlying provider 
    Membership.Provider = new MockMembershipProvider(); 
} 

回答

8

定義一個成員的接口,這樣的事情:

public interface IMembershipProvider 
{ 
    void CreateUser(string username, string password); 
} 

...實現它爲你的MVC應用程序是這樣的:

public class AspDotNetMembershipProvider : IMembershipProvider 
{ 
    public void CreateUser(string username, string password) 
    { 
     string createStatus; 

     Membership.CreateUser(
      username, 
      password, 
      username, 
      null, 
      null, 
      true, 
      null, 
      out createStatus); 

     // throw an exception if createStatus isn't as expected 
    } 
} 

...再注入到您的控制器和使用它是這樣的:

public class AccountController 
{ 
    private readonly IMembershipProvider _membershipProvider; 

    public AccountController(IMembershipProvider membershipProvider) 
    { 
     this._membershipProvider = membershipProvider; 
    } 

    public ActionResult Register(RegistrationModel model) 
    { 
     // Try and catch this, returning a success ActionResult if it worked: 
     this._membershipProvider.CreateUser(model.Email, model.Password); 
    } 
} 

ASP.NET使用靜態類如Membership來處理很多事情,但靜態類訪問總是會使單元測試變得困難。標準的解決方案是爲服務定義一個接口,使用靜態ASP.NET類實現它,並將其注入到控制器中。

您可以使用默認DependencyResolver和DI容器如Unity來設置注射(如果您尚未註冊)。

+1

不應該'AspDotNetMembershipProvider'實現接口?像公共類AspDotNetMembershipProvider:IMembershipProvider {...' – marapet 2012-02-05 21:52:50

+0

糟糕,當然它應該。更正,謝謝:) – 2012-02-05 22:20:54

+0

'Membership'類是靜態的......但潛在的供應商是通過ASP運行時設置......我想,我也可以設置它 – 2012-02-06 10:23:05

0

控制器的單元測試不應使用您的CustomMembershipProvider或標準SQL提供程序。如果執行單元測試,您應該使用存根/僞造,您可以完全控制它返回的內容。如果您在測試中使用真正的提供商,那麼它不再是單元測試,而是集成測試。

爲了實現單元可測試性,您需要定義一個假提供者,可以使用Mocking框架,也可以手動滾動僞造「罐裝」結果。假可能是這個樣子:

public class FakeMembershipProvider : MembershipProvider 
{ 
    public MembershipCreateStatus CreateStatus = MembershipCreateStatus.Success; 

    public void CreateUser((string username, string password, string email, 
     string passwordQuestion, string passwordAnswer, bool isApproved, 
     object providerUserKey, out MembershipCreateStatus status) 
    { 
     status = CreateStatus; 
    } 

    ... 
} 

讓控制器把供應商作爲一個構造函數參數

public class AccountController 
{ 
    private readonly MembershipProvider _membershipProvider; 

    public AccountController(MembershipProvider membershipProvider) 
    { 
     _membershipProvider = membershipProvider; 
    } 

    public ActionResult Register(RegistrationModel model) 
    { 
     MembershipCreateStatus result; 
     _membershipProvider.CreateUser(model.Email, model.Password, ..., out result); 

     return View(/*Make this depend on the result*/); 
    } 
} 

在單元測試中,你要設置根據你要測試什麼,假可以斷言,你希望每個登記結果的結果:

[Test] 
void Should_display_success_view_when_user_successfully_created() 
{ 
    var membershipProvider = new FakeMembershipProvider(); 
    membershipProvider.CreateStatus = MembershipCreateStatus.Success; 
    var controller = new AccountController(membershipProvider); 
    var model = new RegistrationModel(); 

    var result = controller.Register(model) as ViewResult; 

    Assert.That(result.Name, Is.EqualTo("ExpectedViewName"));  
} 

由於的MembershipProvider是相當大的,你很可能不會使用所有的它也可以是無線se使用包裝Membership類的@SteveWilkes方法來創建更小更有針對性的界面。另外一個模擬框架爲您節省了大量工作。爲了將控制器連接到新的依賴關係,您必須創建一個新的ControllerFactory。

2

我已經創建已BREAKEN分解成三種不同的接口更有條理的成員提供(與者正在使用DependencyResolver解決這些問題)。

它可以很容易地進行單元測試的提供商。只需測試您的IAccountRepository的實施。

你可以閱讀一下:http://blog.gauffin.org/2011/09/a-more-structured-membershipprovider/

或只需安裝NuGet包:

install-package griffin.mvccontrib