C# 如何使用ASP.NET Identity 3对ASP.NET 5帐户控制器进行单元测试
我想单元测试使用ASP.NET Identity 3的ASP.NET 5帐户控制器,但我不确定最好的方法是什么。我的帐户控制器正在使用UserManager,正如我所看到的,这个UserManager类没有一个可以用来模拟它的接口,我已经检查了源代码。我认为的一种方法是将其包装到另一个实现接口的类中,然后使用该类进行模拟。这是使account controller单元可测试的唯一方法还是其他更好的方法。请注意,我指的不是需要使用数据库的集成测试。这是我必须要做的,才能使它工作。我完全抽象了接口后面的身份模型,使其持久化C# 如何使用ASP.NET Identity 3对ASP.NET 5帐户控制器进行单元测试,c#,asp.net,asp.net-mvc,unit-testing,C#,Asp.net,Asp.net Mvc,Unit Testing,我想单元测试使用ASP.NET Identity 3的ASP.NET 5帐户控制器,但我不确定最好的方法是什么。我的帐户控制器正在使用UserManager,正如我所看到的,这个UserManager类没有一个可以用来模拟它的接口,我已经检查了源代码。我认为的一种方法是将其包装到另一个实现接口的类中,然后使用该类进行模拟。这是使account controller单元可测试的唯一方法还是其他更好的方法。请注意,我指的不是需要使用数据库的集成测试。这是我必须要做的,才能使它工作。我完全抽象了接口后
我创建了一些默认类,它们基本上包装了标识模型,允许我将紧密耦合分离到标识3,从而允许模拟并使控制器单元可测试。实际上,有一个工具,它不仅允许模拟接口。您几乎可以模拟和测试任何东西,而无需创建大量包装器或接口等。有两种方法可以做到这一点 模拟框架
UserManager
不是密封类。您可以使用现有的框架,如NSubstitute、mock等,将虚拟用户管理器注入到调用代码中。大多数框架(据我所知)都支持在mock中重写非密封类的行为,只要该方法被标记为virtual
,而UserManager
上的几乎所有这些方法都有这样的标记。下面是一个如何使用NSubstitute(我选择的框架)的示例
正如您所指出的,该类没有实现IUserManager
接口,但没有密封,因此您可以创建自己的实现。您的实现可以实现一个接口,该接口可以在原始的UserManager
类上指定现有方法,然后您可以使用来实现该接口
示例方法签名,然后是您的实现
用户管理器上的方法
公共虚拟任务CreateIdentityAsync(用户,字符串身份验证类型)
方法(在本例中为强类型)
Task CreateIdentityAsync(MyUserType用户,string authenticationType);
具体类上的实现(本例中为强类型)
异步任务IMyUserTypeManager.CreateIdentityAsync(MyUserType用户,字符串身份验证类型)
{
return wait this.CreateIdentityAsync(用户,authenticationType);
}
使用您的控制器创建模拟与上面第一个示例中所示的相同
这种方法的好处是:
这种方法的缺点是您必须创建和维护身份代码的代理,但通常您实际使用/调用的方法数量相当有限,因此不需要做更多的工作。实际上,这只是一种方法。这就是为什么这些测试被称为“单元测试”。单元意味着测试单个单元,而不是单元之间的集成。您正在实现的登录是一个单独的单元,标识和身份验证-另一个单元。
var uManager = NSubstitute.Substitute.For<UserManager<MyUserType, int>>();
var result = new ClaimsIdentity();
uManager.CreateIdentityAsync(NSubstitute.Arg.Any<MyUserType>(), "login").Returns(Task.FromResult(result));
var controller = new MyAuthController(uManager);
controller.DoSomething();
public class UserManager<TUser, TKey> : IDisposable where TUser : class, IUser<TKey> where TKey : IEquatable<TKey>
public virtual Task<ClaimsIdentity> CreateIdentityAsync(TUser user, string authenticationType)
Task<ClaimsIdentity> CreateIdentityAsync(MyUserType user, string authenticationType);
async Task<ClaimsIdentity> IMyUserTypeManager.CreateIdentityAsync(MyUserType user, string authenticationType)
{
return await this.CreateIdentityAsync(user, authenticationType);
}