I'm creating basic unit tests for my project. For some reason, I keep getting a NullReferenceException when testing that I get a ControllerBase.Problem(String, String, Nullable<Int32>, String, String)
response. I'm sure the problem is a discrepancy from the controller not actually running, as it seems to behave perfectly fine when the controller is running.
Controller:
[HttpGet("{id}")]
[Produces("application/json")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public IActionResult GetPatient([GuidNotEmpty] Guid id)
{
Patient patient = null;
patient = _patientDbService.FindPatient(id);
if (patient == null) {
return Problem("Patient not found.", string.Empty, StatusCodes.Status404NotFound,
"An error occurred.", "https://tools.ietf.org/html/rfc7231#section-6.5.1");
}
return Ok(patient);
}
Test:
[Fact]
public void TestGetPatientFromIdPatientNotFound()
{
// Act
IActionResult result = _patientController.GetPatient(Guid.NewGuid());
// Assert
Assert.IsType<ObjectResult>(result);
Assert.NotNull(((ObjectResult)result).Value);
Assert.IsType<ProblemDetails>(((ObjectResult)result).Value);
Assert.Equal(((ObjectResult)result).StatusCode, StatusCodes.Status404NotFound);
}
Result:
X PatientServiceTest.PatientServiceUnitTest.TestGetPatientFromIdPatientNotFound [1ms]
Error Message:
System.NullReferenceException : Object reference not set to an instance of an object.
Stack Trace:
at Microsoft.AspNetCore.Mvc.ControllerBase.Problem(String detail, String instance, Nullable`1 statusCode, String title, String type)
at PatientService.Controllers.PatientController.GetPatient(Guid id) in /home/surafel/coding/microservices-dev/c#/PatientService/Controllers/PatientController.cs:line 43
at PatientServiceTest.PatientServiceUnitTest.TestGetPatientFromIdPatientNotFound() in /home/surafel/coding/microservices-dev/c#/PatientServiceTest/PatientServiceUnitTest.cs:line 69
As pointed out by Aluan Haddad in the comments, the that Problem()
calls ProblemDetailsFactory
to create the ProblemDetails
objects, which is supplied by the service manager. The service manager only works when the application is running:https://github.com/dotnet/aspnetcore/blob/master/src/Mvc/Mvc.Core/src/ControllerBase.cs#L194
The ControllerBase.ProblemDetailsFactory
variable can be set, so I created a mock ProblemDetailsFactory
instance and set the controllers factory to an instance of my mock. This seems to make it work.
Mock:
public class MockProblemDetailsFactory : ProblemDetailsFactory
{
public MockProblemDetailsFactory()
{
}
public override ProblemDetails CreateProblemDetails(HttpContext httpContext,
int? statusCode = default, string title = default,
string type = default, string detail = default, string instance = default)
{
return new ProblemDetails() {
Detail = detail,
Instance = instance,
Status = statusCode,
Title = title,
Type = type,
};
}
public override ValidationProblemDetails CreateValidationProblemDetails(HttpContext httpContext,
ModelStateDictionary modelStateDictionary, int? statusCode = default,
string title = default, string type = default, string detail = default,
string instance = default)
{
return new ValidationProblemDetails(new Dictionary<string, string[]>()) {
Detail = detail,
Instance = instance,
Status = statusCode,
Title = title,
Type = type,
};
}
}
I added this line in the setup for this unit tests, and it solves the problem.
_patientController.ProblemDetailsFactory = new MockProblemDetailsFactory();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With