[英]How to test ASP.NET MVC 3 authentication when using Membership
我想测试我的AccountController
。 问题是在Register方法中我使用下一行来创建用户:
Membership.CreateUser(model.Email, model.Password, model.Email, null, null, true, null, out createStatus);
在Web应用程序中,我使用了我使用web.config设置的CustomMembershipProvider
。 在我的单元测试标准SqlMembershipProvider
Membership类中。 而不是我在我的应用程序中使用的CustomMembershipProvider
。
如何在单元测试环境中设置成员资格? 我的意思是以编程方式设置它,因为asp net在读取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();
}
定义成员资格界面,如下所示:
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
这样的静态类Membership
许多事情,但静态类访问总是使单元测试变得困难。 标准解决方案是为服务定义接口,使用静态ASP.NET类实现它,并将其注入控制器。
您可以使用默认的DependencyResolver
和像Unity这样的DI容器来设置注入(如果您还没有)。
我已经创建了一个更加结构化的成员资格提供程序,它已被分解为三个不同的接口(并且提供程序使用DependencyResolver
解析它们)。
它使得提供者的单元测试变得容易。 只需测试您的IAccountRepository
实现。
你可以在这里阅读: http : //blog.gauffin.org/2011/09/a-more-structured-membershipprovider/
或者只是安装nuget包:
install-package griffin.mvccontrib
您对控制器的单元测试不应使用CustomMembershipProvider
或标准SQL提供程序。 如果执行单元测试,您应该使用Stub / Fake,您可以完全控制它返回的内容。 如果您在测试中使用真正的提供程序,它不再是单元测试,它是一个集成测试。
为了实现单元可测试性,您需要定义一个假提供程序,使用模拟框架或手动滚动带有“固定”结果的假冒。 假货看起来像这样:
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;
}
...
}
让控制器将提供者作为ctor参数
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非常庞大并且您可能不会全部使用它,因此使用@SteveWilkes包装Membership类来创建更小的更具针对性的接口是明智的。 另外一个模拟框架可以为您节省大量工作。 为了使用新的依赖关系连接控制器,您必须创建一个新的ControllerFactory。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.