MVC5中用于模拟ConfirmEmailAsync和其他UserManager方法的接口 [英] Interfaces for mocking ConfirmEmailAsync and other UserManager methods in MVC5
问题描述
我正在尝试对该控制器方法进行单元测试,该方法在当前的MVC项目中是开箱即用的.
I am trying to unit test this controller method, which comes out of the box in current MVC projects.
[AllowAnonymous]
public async Task<ActionResult> ConfirmEmail(string userId, string code)
{
if (userId == null || code == null)
{
return View("Error");
}
var result = await UserManager.ConfirmEmailAsync(userId, code);
return View(result.Succeeded ? "ConfirmEmail" : "Error");
}
AccountController具有一个构造函数,该构造函数将使用ApplicationUserManager和ApplicationSignInManager作为参数,以及带有专用设置程序的匹配属性以用于测试.但是,我不知道如何模拟出ConfirmEmailAsync方法.
The AccountController has a constructor which will take an ApplicationUserManager and a ApplicationSignInManager as parameters, and the matching properties with private setters to use for testing. However, I can't figure out how to mock out the ConfirmEmailAsync method.
您可以在Identity名称空间中模拟各种接口:
You can mock various interfaces in the Identity namespace:
var store = new Mock<IUserStore<ApplicationUser>>();
store.As<IUserEmailStore<ApplicationUser>>()
.Setup(x => x.FindByIdAsync("username1"))
.ReturnsAsync((ApplicationUser)null);
var mockManager = new ApplicationUserManager(store.Object);
AccountController ac = new AccountController(mockManager, null, GetMockRepository().Object, GetMockLogger().Object);
但是我无法找到或弄清楚我需要哪个接口来创建ConfirmEmailAsync的模拟程序.
But I can't find or figure out which Interface I need in order to create a mock of ConfirmEmailAsync.
我该如何处理?作为参考,是否有一种很好的方法可以找出这些方法在哪个接口上进行模拟和测试?
How do I go about this? And for reference, is there a good way of finding out which interfaces these methods are on in order to mock and test them?
推荐答案
ConfirmEmailAsync
当前不属于框架接口的一部分.它在UserManager<TUser, TKey>
类中,该类是Identity框架的基类.
ConfirmEmailAsync
is not currently part of an interface in the framework. It's in the UserManager<TUser, TKey>
class which is the base class of Identity framework.
我的解决方案?
提取所有内容
我通过将大多数身份功能抽象到自己的项目中来解决此问题,以便我可以更轻松地进行单元测试并在其他项目中重用抽象.阅读这篇文章后,我有了主意
I got around this by abstracting most of the functionality of identity into its own project so that I can unit test it easier and reuse the abstraction in other projects. I got the idea after reading this article
Persistence-Ignorant ASP.NET Identity with Patterns
然后我微调了这个想法以适应我的需求.我基本上只是从asp.net.identity中交换了我需要的所有内容,用于我的自定义接口,该接口或多或少地反映了框架提供的功能,但具有易于模拟的优点.
I then fine tuned the idea to suit my needs. I basically just swapped everything i needed from asp.net.identity for my custom interfaces which more or less mirrored the functionality provided by the framework but with the advantage of easier mockability.
IIdentityUser
IIdentityUser
/// <summary>
/// Minimal interface for a user with an id of type <seealso cref="System.String"/>
/// </summary>
public interface IIdentityUser : IIdentityUser<string> { }
/// <summary>
/// Minimal interface for a user
/// </summary>
public interface IIdentityUser<TKey>
where TKey : System.IEquatable<TKey> {
TKey Id { get; set; }
string UserName { get; set; }
string Email { get; set; }
bool EmailConfirmed { get; set; }
string EmailConfirmationToken { get; set; }
string ResetPasswordToken { get; set; }
string PasswordHash { get; set; }
}
IIdentityManager
IIdentityManager
/// <summary>
/// Exposes user related api which will automatically save changes to the UserStore
/// </summary>
public interface IIdentityManager : IIdentityManager<IIdentityUser> { }
/// <summary>
/// Exposes user related api which will automatically save changes to the UserStore
/// </summary>
public interface IIdentityManager<TUser> : IIdentityManager<TUser, string>
where TUser : class, IIdentityUser<string> { }
/// <summary>
/// Exposes user related api which will automatically save changes to the UserStore
/// </summary>
public interface IIdentityManager<TUser, TKey> : IDisposable
where TUser : class, IIdentityUser<TKey>
where TKey : System.IEquatable<TKey> {
Task<IIdentityResult> AddPasswordAsync(TKey userid, string password);
Task<IIdentityResult> ChangePasswordAsync(TKey userid, string currentPassword, string newPassword);
Task<IIdentityResult> ConfirmEmailAsync(TKey userId, string token);
//...other code removed for brevity
}
IIdentityResult
IIdentityResult
/// <summary>
/// Represents the minimal result of an identity operation
/// </summary>
public interface IIdentityResult : System.Collections.Generic.IEnumerable<string> {
bool Succeeded { get; }
}
在身份管理器的默认实现中,我只包装了ApplicationManager
,然后在我的类型与asp.net.identity类型之间映射了结果和功能.
In my default implementation of the identity manager i simply wrapped the ApplicationManager
and then mapped results and functionality between my types and the asp.net.identity types.
public class DefaultUserManager : IIdentityManager {
private ApplicationUserManager innerManager;
public DefaultUserManager() {
this.innerManager = ApplicationUserManager.Instance;
}
//..other code removed for brevity
public async Task<IIdentityResult> ConfirmEmailAsync(string userId, string token) {
var result = await innerManager.ConfirmEmailAsync(userId, token);
return result.AsIIdentityResult();
}
//...other code removed for brevity
}
这篇关于MVC5中用于模拟ConfirmEmailAsync和其他UserManager方法的接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!