C# Asp.Net MVC Core - Unit testing ErrorController using RouteData() in XUnit (&Moq)

67 Views Asked by At

I have an ErrorController:

public class ErrorController : Controller
{
private readonly ILogger<ErrorController> _logger;

public ErrorController(ILogger<ErrorController> logger)
{
    _logger = logger;
}

[Route("/Error/{statusCode}")]
public IActionResult HttpStatusCodeHandler(int statusCode)
{
    var statusCodeResult = HttpContext.Features.Get<IStatusCodeReExecuteFeature>();

    switch (statusCode)
    {
        case 400:
            ViewBag.ErrorMessage = "Bad Request. The server could not understand the request.";
            _logger.LogWarning($"400 Error Occurred. Path = {statusCodeResult.OriginalPath}" +
                               $" and QueryString = {statusCodeResult.OriginalQueryString}");
            break;

        case 401:
            ViewBag.ErrorMessage = "Unauthorized. You are not authorized to access the requested resource.";
            _logger.LogWarning($"401 Error Occurred. Path = {statusCodeResult.OriginalPath}" +
                               $" and QueryString = {statusCodeResult.OriginalQueryString}");
            break;

        case 403:
            ViewBag.ErrorMessage = "Forbidden. You do not have permission to access the requested resource.";
            _logger.LogWarning($"403 Error Occurred. Path = {statusCodeResult.OriginalPath}" +
                               $" and QueryString = {statusCodeResult.OriginalQueryString}");
            break;

        case 404:
            ViewBag.ErrorMessage = "Not Found. The resource you requested could not be found.";
            _logger.LogWarning($"404 Error Occurred. Path = {statusCodeResult.OriginalPath}" +
                               $" and QueryString = {statusCodeResult.OriginalQueryString}");
            break;

        case 500:
            ViewBag.ErrorMessage = "Internal Server Error. An unexpected error occurred on the server.";
            _logger.LogError($"500 Error Occurred. Path = {statusCodeResult.OriginalPath}" +
                             $" and QueryString = {statusCodeResult.OriginalQueryString}");
            break;

        default:
            ViewBag.ErrorMessage = "An error occurred while processing your request.";
            _logger.LogError($"Error {statusCode} occurred. Path = {statusCodeResult.OriginalPath}" +
                             $" and QueryString = {statusCodeResult.OriginalQueryString}");
            break;
    }

    return View("Error");
}

[Route("/Error")]
public IActionResult ErrorHandler()
{
    var statusCodeResult = HttpContext.Features.Get<IStatusCodeReExecuteFeature>();

    if(statusCodeResult != null)
    {
        var statusCodeResultErrorMessage = $"Error occurred. Path = {statusCodeResult.OriginalPath} and QueryString = {statusCodeResult.OriginalQueryString}";

        _logger.LogError(statusCodeResultErrorMessage);
    }

    ViewBag.ErrorMessage = "Sorry, an error occurred.";

    return View("Error");
}

}

I am trying to unit test it using XUnit and Moq. Here are my unit tests:

using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.Extensions.Logging;

namespace UnitTests;

public class ErrorControllerTests
{
[Fact]
public void HttpStatusCodeHandler_ReturnsViewWithErrorMessage_For404()
{
    // Arrange
    var loggerMock = new Mock<ILogger<ErrorController>>();
    var controller = new ErrorController(loggerMock.Object);
    var httpContext = new DefaultHttpContext();
    var routeData = new RouteData();
    routeData.Values["statusCode"] = 404;
    var actionContext = new ActionContext(httpContext, routeData, new ControllerActionDescriptor());

    controller.ControllerContext = new ControllerContext(actionContext);

    // Act
    var result = controller.HttpStatusCodeHandler(404) as ViewResult;

    // Assert
    Assert.NotNull(result);
    Assert.Equal("Error", result.ViewName);
    Assert.Equal("Sorry, the resource you requested could not be found.", result.ViewData["ErrorMessage"]);

    // Verify logging
    loggerMock.Verify(logger => logger.LogError("Resource not found. Status code: 404"), Times.Once);
}

[Fact]
public void HttpStatusCodeHandler_ReturnsViewWithGenericErrorMessage_ForOtherStatusCodes()
{
    // Arrange
    var loggerMock = new Mock<ILogger<ErrorController>>();
    var controller = new ErrorController(loggerMock.Object);
    var httpContext = new DefaultHttpContext();
    var routeData = new RouteData();
    routeData.Values["statusCode"] = 500;
    var actionContext = new ActionContext(httpContext, routeData, new ControllerActionDescriptor());

    controller.ControllerContext = new ControllerContext(actionContext);

    // Act
    var result = controller.HttpStatusCodeHandler(500) as ViewResult;

    // Assert
    Assert.NotNull(result);
    Assert.Equal("Error", result.ViewName);
    Assert.Equal("An error occurred while processing your request.", result.ViewData["ErrorMessage"]);

    // Verify logging
    loggerMock.Verify(logger => logger.LogError("An error occurred. Status code: 500"), Times.Once);
}
}

However, I don't understand how to declare the "RouteData()"? I am getting the following error in my code (and it won't build).

The RouteData error is "There is no argument given that responds to the required parameter of pageType of 'RouteData.RouteData(Type, IReadOnlyDictionary<string, object?>)'"

Any help would be greatly appreciated, thank you.

1

There are 1 best solutions below

0
Goober On

I was using an incorrect namespace of "Microsoft.AspNetCore.Components", but it should have been "Microsoft.AspNetCore.Routing". Resolved.