Я создаю веб-API в ASP.NET Core и хочу провести модульное тестирование контроллеров.
Я ввожу интерфейс для доступа к данным, над которым я легко могу имитировать. Но контроллер должен проверить заголовки в запросе на токен, и этот запрос, похоже, не существует, когда я просто создаю экземпляр контроллера сам, и он также доступен только для получения, поэтому я даже не могу его вручную установить. Я нашел множество примеров имитации ApiController, но это не ядро .NET. Также много руководств и примеров того, как проводить модульное тестирование контроллеров ядра .NET, но ни один из них на самом деле не использовал HttpRequest.
Я построил MCVE, чтобы продемонстрировать это:
[Produces("application/json")]
[Route("api/Players")]
public class PlayersController : Controller
{
private IAccessor accessor;
public PlayersController(IAccessor ac = null):base()
{
accessor = ac ?? AccessorFactory.GetAccessor();
}
/// <summary>
/// Get all players. Must be logged in.
/// </summary>
/// <returns>Ok or Unauthorized.</returns>
[HttpGet]
public IActionResult Get()
{
Player client = accessor.GetLoggedInPlayer(Request.Headers["token"]); // NRE here because Request is null
if (client == null) return Unauthorized();
return Ok(accessor.GetAllPlayers());
}
}
Я использую Moq и MSTest в своем тестовом проекте и внедряю имитацию IAccessor. Как мне ввести запрос или инициализировать его с помощью контроллера? Думаю, моим последним средством было бы размышление, но я действительно хочу избежать этого.
При создании экземпляра тестируемого контроллера обязательно назначьте HttpContext
, который содержит необходимые зависимости для выполнения теста до завершения.
Вы можете попробовать издеваться над HttpContext
и предоставить это контроллеру или просто использовать DefaultHttpContext
, предоставленный фреймворком.
//Arrange
var mockedAccessor = new Mock<IAccessor>();
//...setup mockedAccessor behavior
//...
var httpContext = new DefaultHttpContext(); // or mock a `HttpContext`
httpContext.Request.Headers["token"] = "fake_token_here"; //Set header
//Controller needs a controller context
var controllerContext = new ControllerContext() {
HttpContext = httpContext,
};
//assign context to controller
var controller = new PlayersController (mockedAccessor.Object){
ControllerContext = controllerContext,
};
//Act
var result = controller.Get();
//...
Вышеизложенное предполагает, что вы уже знаете, как имитировать зависимости контроллера, такие как IAccessor
, и было предназначено для демонстрации того, как предоставить зависимости, специфичные для платформы, необходимые для теста.
@Nikosi можешь проверить это ссылка на сайт
Я также слышал, что http-контекст не следует издеваться над тестами. Поэтому я хотел бы подчеркнуть предложение использовать DefaultHttpContext вместо того, чтобы пытаться издеваться над ним.
Возможный дубликат Mock HttpContext для модульного тестирования контроллера MVC ядра .NET?