Как я могу проверить контроллер, который использует идентичность со свойством только для чтения? - PullRequest
0 голосов
/ 07 января 2020

У меня есть следующий код:

[Route("resources/avatar")]
[ApiController]
public class AvatarController : ControllerBase
{
    private readonly ApplicationDbContext database;
    private readonly IWebHostEnvironment environment;
    private readonly IUserManagerWrapper userManagerWrapper;

    public AvatarController(IUserManagerWrapper userManagerWrapper, IWebHostEnvironment environment,
        ApplicationDbContext database)
    {
        this.userManagerWrapper = userManagerWrapper;
        this.environment = environment;
        this.database = database;
    }

    [HttpGet]
    [Route("")]
    public async Task<IActionResult> Index()
    {
        if (User == null) return DefaultImage();

        var user = await this.userManagerWrapper.GetUserAsync(User);
        if ((user?.Avatar?.Length ?? 0) == 0) return DefaultImage();

        return File(user.Avatar, "image/jpeg");
    }
}

У меня возникла проблема с проверкой этого Index Page.

User - это property, полученное из ControllerBase и имеет тип ClaimsPrincipal.

Я использовал wrapper, где я бы обернул usermanager, а затем использовал interface, который я бы mock.

Проблема с этим подходом заключается в том, что я не могу установить ClaimsPrincipal на null, потому что это read-only.

Это был мой тест:

[TestFixture]
public class AvatarController_Should
{
    [Test]
    public async Task IndexReturnsDefaultImage()
    {
        var hostingEnvironmentMock = new Mock<IWebHostEnvironment>();
        var dabataseName = nameof(IndexReturnsDefaultImage);
        var options = AvatarTestUtil.GetOptions(dabataseName);
        var userManagerWrapperMock = new Mock<IUserManagerWrapper>();

        using (var actAndAssertContext = new ApplicationDbContext(options))
        {
            var sut = new AvatarController(userManagerWrapperMock.Object, hostingEnvironmentMock.Object, actAndAssertContext);
        }
     }
}
   public class AvatarTestUtil
   {
    public static DbContextOptions<ApplicationDbContext> GetOptions(string databaseName)
    {
        var serviceCollection = new ServiceCollection()
            .AddEntityFrameworkInMemoryDatabase()
            .BuildServiceProvider();

        return new DbContextOptionsBuilder<ApplicationDbContext>()
            .UseInMemoryDatabase(databaseName)
            .UseInternalServiceProvider(serviceCollection)
            .Options;
    }
}

}

Я открыт для использования совершенно нового подхода.

Так я раньше тестировал на identity, но сейчас я застрял.

1 Ответ

2 голосов
/ 07 января 2020

Глядя на исходный код ControllerBase, мы видим, что Пользователь определен следующим образом:

public ClaimsPrincipal User => HttpContext?.User;

Таким образом, Пользователь фактически происходит из HttpContext. Но HttpContext также доступен только для чтения. Однако, углубившись в исходный код, мы видим, что HttpContext является производным от ControllerContext

public HttpContext HttpContext => ControllerContext.HttpContext;

Увы! ControllerContext на самом деле имеет установщик в конкретной реализации!

public ControllerContext ControllerContext { get; set; }

Мы могли бы установить совершенно новый ControllerContext, если бы захотели. Но нам действительно нужен ControllerContext.User. К счастью, у этого тоже есть сеттер. Поскольку вам действительно нужно установить User, мы можем сделать это прямо здесь, а не обновлять другой ControllerContext.

using (var actAndAssertContext = new ApplicationDbContext(options))
{
     var sut = new AvatarController(userManagerWrapperMock.Object, hostingEnvironmentMock.Object, actAndAssertContext);
     sut.ControllerContext.HttpContext.User = null;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...