MVC5 中用于模拟 ConfirmEmailAsync 和其他 UserManager 方法的接口 [英] Interfaces for mocking ConfirmEmailAsync and other UserManager methods in MVC5

查看:21
本文介绍了MVC5 中用于模拟 ConfirmEmailAsync 和其他 UserManager 方法的接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试对这个控制器方法进行单元测试,它在当前的 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 作为参数,以及与私有 setter 匹配的属性用于测试.但是,我不知道如何模拟 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 类中,该类是 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

具有模式的持久性无知 ASP.NET 身份

然后我微调了这个想法以满足我的需求.我基本上只是将我需要的一切从 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.

身份用户

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

身份管理器

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

IdentityResult

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆