如何使用Microsoft Fakes(垫片)为await / async方法创建假货/模拟?

时间:2014-04-26 06:27:48

标签: c# unit-testing asynchronous asp.net-mvc-5 microsoft-fakes

当您创建一个新的MVC 5项目时,您将获得一个包含Login方法的帐户控制器(AccountController)。我的问题是:你将如何使用Microsoft Fakes(Shim)创建单元测试以测试此方法?

[HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
    {
        if (ModelState.IsValid)
        {
            var user = await UserManager.FindAsync(model.UserName, model.Password);
            if (user != null)
            {
                await SignInAsync(user, model.RememberMe);
                return RedirectToLocal(returnUrl);
            }
            else
            {
                ModelState.AddModelError("", "Invalid username or password.");
            }
        }

        // If we got this far, something failed, redisplay form
        return View(model);
    }

所以我创建了这个测试方法但是我无法进入登录方法并且在第一次调用后执行停止。这是我的单元测试:

[TestMethod]
    public void Test1()
    {
        using (ShimsContext.Create())
        {
            var shimUserManager = new ShimUserManager<ApplicationUser>();
            shimUserManager.FindAsyncStringString = (x, y) => { return new Task<ApplicationUser>(null); };

            var ctrl = new AccountController(shimUserManager);
            var result = ctrl.Login(new Models.LoginViewModel { UserName = "user", Password = "pass" }, "");
        }
    } 

我为Microsoft.AspNet.Identity.Core程序集

创建了一个假/垫片

1 个答案:

答案 0 :(得分:0)

您可以使用MVC的依赖注入机制创建一个接口IUserManager并将其实现注入您的控制器。该实现将简单地调用UserManager.FindAsync方法。然后,您将能够在单元测试中模拟此调用。

实施例

public interface IUserManager
{
    User Find(string username, string password);
}

public class UserManagerImpl : IUserManager
{
    public User Find(string username, string password)
    {
        return await UserManager.FindAsync(username, password);
    }
}

public class AccountController
{
    private IUserManager _userManager;

    public AccountController(IUserManager userManager)
    {
        _userManager = userManager;
    }
    //user _userManager on your Login method.
}