У приложения ASP.NET-MVC + ASP.NET-WebAPI2 + ASP.NET-Identity 1 есть api-метод Get:
[Route("api/accounts")]
[HttpGet]
public HttpResponseMessage Get()
{
var user = _dbContext.Users.Find(User.Identity.GetUserId());
if(user.Roles.Count > 0)
{
var userRoles = user.Roles.Select(x => x.Role.Name);
var model = new ApiViewModel
{
UserName = User.Identity.Name,
UserRoleNames = userRoles
};
return Request.CreateResponse(HttpStatusCode.OK, model);
}
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "The user has no one role");
}
Хочу протестировать этот метод. Для данного метода необходимо, чтобы в контексте запроса был авторизованный пользователь. Я решил попробовать замокать вызов User.Identity.GetUserId() - получить Id существующего в БД пользователя:
[TestMethod()]
public void GetTest()
{
//Arrange
var mockPrincipal = new Mock<IPrincipal>();
var mockIdentity = new Mock<IIdentity>();
mockPrincipal.SetupGet(x => x.Identity).Returns(mockIdentity.Object);
mockIdentity.Setup(x => x.GetUserId()).Returns("5dcf65f5-2e42");
...
И в ответ получил исключение:
Expression references a method that does not belong to the mocked object: x => x.GetUserId()
Есть ли возможность замокать вызов метода расширения или есть ли другой способ передать в контекст запроса Get авторизованного пользователя?
Обновил юнит-тест, согласно ответу @Pavel Mayorov:
[TestMethod()]
public void GetTest()
{
//Arrange
var mockIdentity = new ClaimsIdentity();
mockIdentity.AddClaim(new Claim(ClaimTypes.NameIdentifier, "5dcf65f5-2e42"));
var mockPrincipal = new ClaimsPrincipal(mockIdentity);
var controller = new AccountController
{
User = mockPrincipal
};
controller.User = mockPrincipal;
//Act
var result = controller.Get();
+ вызов User.Identity.GetUserId() возвращает 5dcf65f5-2e42 что и требовалось.
- но дальше Find (_dbContext.Users.Find(User.Identity.GetUserId())) возвращает null.
Почему во время теста? при передачи валидного Id Find вернул null.
Этот метод ищет среди прочих утверждений (Claims) утверждение с именем ClaimTypes.NameIdentifier. Кстати, IIdentity - это объект-носитель данных, а не сервис, и мокать его нет смысла.
Поэтому проще всего создать новую ClaimsIdentity и добавить ей нужные утверждения:
var mockIdentity = new ClaimsIdentity();
mockIdentity.AddClaim(new Claim(ClaimTypes.NameIdentifier, "5dcf65f5-2e42"));
var mockPrincipal = new ClaimsPrincipal(mockIdentity);
Сборка персонального компьютера от Artline: умный выбор для современных пользователей