Let\'s assume this is my action method
public IHttpActionResult Get(int id)
{
var status = GetSomething(id);
if (status)
{
return Ok();
After a few hours of research and trying, I finally figured out how to fully test my Web API 2 methods that return IHttpActionResult and use the OWIN middleware and the default implementation of ASP.NET Identity.
I will be testing the Get() method on the following ApiController:
public class AccountController : ApiController
{
private ApplicationUserManager _userManager;
public ApplicationUserManager UserManager => _userManager ?? HttpContext.Current.GetOwinContext().GetUserManager();
[Route("api/account"), HttpGet]
public async Task Get()
{
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
if (user == null)
{
ModelState.AddModelError(ModelStateConstants.Errors, "Account not found! Try logging out and in again.");
return BadRequest(ModelState);
}
var roles = await UserManager.GetRolesAsync(user.Id);
var accountModel = new AccountViewModel
{
FullName = user.FullName,
Email = user.Email,
Phone = user.PhoneNumber,
Organization = user.Organization.Name,
Role = string.Join(", ", roles)
};
return Ok(accountModel);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (_userManager != null)
{
_userManager.Dispose();
_userManager = null;
}
}
base.Dispose(disposing);
}
}
Start with a base class that all test classes will inherit from:
public class BaseTest
{
protected static User CurrentUser;
protected static IList Roles;
public BaseTest()
{
var email = "unit@test.com";
CurrentUser = new User
{
FullName = "Unit Tester",
Email = email,
UserName = email,
PhoneNumber = "123456",
Organization = new Organization
{
Name = "Test Organization"
}
};
Roles = new List
{
"Administrator"
};
}
protected void InitializeApiController(ApiController apiController)
{
//Init fake controller Http and Identity data
var config = new HttpConfiguration();
var request = new HttpRequestMessage();
var routeData = new HttpRouteData(new HttpRoute(""));
apiController.ControllerContext = new HttpControllerContext(config, routeData, request)
{
Configuration = config
};
apiController.User = new GenericPrincipal(new GenericIdentity(""), new[] { "" });
//Initialize Mocks
var appUserMgrMock = GetMockedApplicationUserManager();
var appSignInMgr = GetMockedApplicationSignInManager(appUserMgrMock);
var appDbContext = GetMockedApplicationDbContext();
//Configure HttpContext.Current.GetOwinContext to return mocks
var owin = new OwinContext();
owin.Set(appUserMgrMock.Object);
owin.Set(appSignInMgr.Object);
owin.Set(appDbContext.Object);
HttpContext.Current = new HttpContext(new HttpRequest(null, "http://test.com", null), new HttpResponse(null));
HttpContext.Current.Items["owin.Environment"] = owin.Environment;
}
private static Mock GetMockedApplicationSignInManager(Mock appUserMgrMock)
{
var authMgr = new Mock();
var appSignInMgr = new Mock(appUserMgrMock.Object, authMgr.Object);
return appSignInMgr;
}
private Mock GetMockedApplicationUserManager()
{
var userStore = new Mock>();
var appUserMgr = new Mock(userStore.Object);
appUserMgr.Setup(aum => aum.FindByIdAsync(It.IsAny())).ReturnsAsync(CurrentUser);
appUserMgr.Setup(aum => aum.GetRolesAsync(It.IsAny())).ReturnsAsync(Roles);
return appUserMgr;
}
private static Mock GetMockedApplicationDbContext()
{
var dbContext = new Mock();
dbContext.Setup(dbc => dbc.Users).Returns(MockedUsersDbSet);
return dbContext;
}
private static IDbSet MockedUsersDbSet()
{
var users = new List
{
CurrentUser,
new User
{
FullName = "Testguy #1",
Email = "test@guy1.com",
UserName = "test@guy1.com",
PhoneNumber = "123456",
Organization = new Organization
{
Name = "Test Organization"
}
}
}.AsQueryable();
var usersMock = new Mock>();
usersMock.As>().Setup(m => m.Provider).Returns(users.Provider);
usersMock.As>().Setup(m => m.Expression).Returns(users.Expression);
usersMock.As>().Setup(m => m.ElementType).Returns(users.ElementType);
usersMock.As>().Setup(m => m.GetEnumerator()).Returns(users.GetEnumerator);
return usersMock.Object;
}
}
The InitializeApiController method contains the meat and potatoes.
Now we can write our tests for AccountController:
public class AccountControllerTests : BaseTest
{
private readonly AccountController _accountController;
public AccountControllerTests()
{
_accountController = new AccountController();
InitializeApiController(_accountController);
}
[Test]
public async Task GetShouldReturnOk()
{
var result = await _accountController.Get();
var response = await result.ExecuteAsync(CancellationToken.None);
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}
}
For everything to work, you'll need to install a bunch of Microsoft.OWIN.* and Microsoft.AspNet.* packages, I'll paste my packages.config here:
The test is very simple, but demonstrates that everything works :-)
Happy testing!