Как замокать метод расширения GetUserId(this IIdentity identity)?

251
07 июля 2017, 03:34

У приложения 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 авторизованного пользователя?

Update

Обновил юнит-тест, согласно ответу @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.

Answer 1

Этот метод ищет среди прочих утверждений (Claims) утверждение с именем ClaimTypes.NameIdentifier. Кстати, IIdentity - это объект-носитель данных, а не сервис, и мокать его нет смысла.

Поэтому проще всего создать новую ClaimsIdentity и добавить ей нужные утверждения:

var mockIdentity = new ClaimsIdentity();
mockIdentity.AddClaim(new Claim(ClaimTypes.NameIdentifier, "5dcf65f5-2e42"));
var mockPrincipal = new ClaimsPrincipal(mockIdentity);
READ ALSO
Как можно вывести полученный url через WebView Unity 3d

Как можно вывести полученный url через WebView Unity 3d

Ситуация такая, url который требуется выводится в DebugLog (http_response

260
Пример использования клиента RIO Sockets

Пример использования клиента RIO Sockets

Прошу привести пример использования RIO сокетов со стороны клиентаНапример, несколько коннектов к разным серверам

188
Hangfire запускать метод в заданное время дня

Hangfire запускать метод в заданное время дня

Здравствуйте! У меня есть массив объектов класса EmployerПочти у всех объектов разные значения времени (Employer

242
Async, await и что я делаю не так?

Async, await и что я делаю не так?

Не очень силён в async/await, не могу понять, что мне студия советует сделать

546