Sul Aga
Sul Aga

Reputation: 6782

How to use Microsoft Fakes (shims) to create fakes/mocks for await/async methods?

When you create a new MVC 5 project you get an account controller (AccountController) which contains Login method. My question is: how will you create a unit test to test this method using 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);
    }

So I have created this test method however I am unable to step into the login method and the execution stops after the first call. Here is my unit test:

[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" }, "");
        }
    } 

I have created a fake/shim for Microsoft.AspNet.Identity.Core assembly

Upvotes: 1

Views: 2138

Answers (1)

Ikaso
Ikaso

Reputation: 2268

You can create an interface IUserManager and inject it's implementation to your controller using MVC's Dependency Injection mechanism. The implementation will simply call the UserManager.FindAsync method. Then you will be able to mock this call in a unit test.

Example

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

Upvotes: 0

Related Questions