Как выполнить модульное тестирование, вызывает ли действие контроллера Core MVC ControllerBase.Problem () - PullRequest
1 голос
/ 18 марта 2020

У нас есть контроллер, производный от ControllerBase с таким действием:

public async Task<ActionResult> Get(int id)
{
  try
  {
    // Logic
    return Ok(someReturnValue);
  }
  catch
  {
    return Problem();
  }
}

У нас также есть модульный тест, подобный этому:

[TestMethod]
public async Task GetCallsProblemOnInvalidId()
{
  var result = sut.Get(someInvalidId);

}

Но ControllerBase.Problem() генерирует исключение Null Reference. Это метод из инфраструктуры Core MVC, поэтому я не знаю, почему он выдает ошибку. Я думаю, что это может быть потому, что HttpContext имеет значение null, но я не уверен. Есть ли стандартизированный способ тестирования контрольного примера, когда контроллер должен вызвать Problem()? Любая помощь приветствуется. Если ответ связан с издевательством: мы используем Moq и AutoFixtrue.

1 Ответ

2 голосов
/ 19 марта 2020

Пустое исключение из-за отсутствия ProblemDetailsFactory

В этом случае контроллер должен иметь возможность создавать ProblemDetails экземпляр с помощью

[NonAction]
public virtual ObjectResult Problem(
    string detail = null,
    string instance = null,
    int? statusCode = null,
    string title = null,
    string type = null)
{
    var problemDetails = ProblemDetailsFactory.CreateProblemDetails(
        HttpContext,
        statusCode: statusCode ?? 500,
        title: title,
        type: type,
        detail: detail,
        instance: instance);

    return new ObjectResult(problemDetails)
    {
        StatusCode = problemDetails.Status
    };
}

Source

ProblemDetailsFactory - это настраиваемое свойство

public ProblemDetailsFactory ProblemDetailsFactory
{
    get
    {
        if (_problemDetailsFactory == null)
        {
            _problemDetailsFactory = HttpContext?.RequestServices?.GetRequiredService<ProblemDetailsFactory>();
        }

        return _problemDetailsFactory;
    }
    set
    {
        if (value == null)
        {
            throw new ArgumentNullException(nameof(value));
        }

        _problemDetailsFactory = value;
    }
}

Источник

, которое можно смоделировать и заполнить при тестировании в изоляции.

[TestMethod]
public async Task GetCallsProblemOnInvalidId() {
    //Arrange
    var problemDetails = new ProblemDetails() {
        //...populate as needed
    };
    var mock = new Mock<ProblemDetailsFactory>();
    mock
        .Setup(_ => _.CreateProblemDetails(
            It.IsAny<HttpContext>(),
            It.IsAny<int?>(),
            It.IsAny<string>(),
            It.IsAny<string>(),
            It.IsAny<string>(),
            It.IsAny<string>())
        )
        .Returns(problemDetails)
        .Verifyable();

    var sut = new MyController(...);
    sut.ProblemDetailsFactory = mock.Object;

    //...

    //Act
    var result = await sut.Get(someInvalidId);

    //Assert
    mock.Verify();//verify setup(s) invoked as expected

    //...other assertions
}
...