XUnit тестирование, проверка исключения
Подскажите как добиться, чтобы не падал тест при проверке на исключение ObjectNotFoundError
Есть сервис, который я мокаю и в настройке пытаюсь добиться симуляции выброса исключения
public async Task GetRequestWithNoSucccessNotFound()
{
var mockService = new Mock<ICompanyService>();
var mockLogger = new Mock<ILogger<CompaniesController>>();
mockService.Setup(service => service.GetCompany(It.IsAny<int>())).Throws<ObjectNotFoundException>();
var controller = new CompaniesController(mockLogger.Object, mockService.Object);
var result = await controller.Get(9999);
var viewResult = Assert.IsType<RequestResponseModel<CompanyViewModel>>(result);
Assert.False(result.IsSuccess);
}
Метод сервиса выглядит так
public async Task<CompanyViewModel> GetCompany(int companyId)
{
var company = await contextDb.Companies.AsNoTracking().Where(p => p.Id == companyId).SelectCompany().FirstOrDefaultAsync();
if (company == null)
{
throw new ObjectNotFoundException();
}
return company;
}
При таком положении вещей, тест падает с ошибкой
System.NullReferenceException : Object reference not set to an instance of an object.
Как мне добиться, чтобы фейковый объект не ронял тест, а выкидывал исключение, которое обрабатывается в контроллере?
UPD
GET
public async Task<RequestResponseModel<CompanyViewModel>> Get(int id)
{
try
{
var company = await CompanyService.GetCompany(id);
return RequestResponseModel<CompanyViewModel>.CreateSuccessObject(company);
}
catch (Exception e)
{
LogError(e);
this.SetErrorResponseStatusCode(e);
return RequestResponseModel<CompanyViewModel>.CreateRequestResponseErrorObject();
}
}
SetErrorResponseStatusCode
public static void SetErrorResponseStatusCode(this ControllerBase controller, Exception exception)
{
// set http status based on type of exception
if (exception is NotImplementedException)
{
controller.Response.StatusCode = (int)HttpStatusCode.NotImplemented;
}
else if (exception is ObjectNotFoundException)
{
controller.Response.StatusCode = (int)HttpStatusCode.NotFound; // вот здесь падает
}
else
{
controller.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
}
}
Хочу отметить, что падает только тест. При обращении к API все корректно работает.
Ответы (1 шт):
Свойство Response равно null, потому что в этот момент ещё не задано.
Следует возвращать нужный ActionResult вместо задания StatusCode.
public static IActionResult ErrorResponseStatusCode(this ControllerBase controller, Exception exception)
{
if (exception is NotImplementedException)
{
return new StatusCodeResult(StatusCodes.Status501NotImplemented);
}
else if (exception is ObjectNotFoundException)
{
return controller.NotFound();
}
else
{
return new StatusCodeResult(StatusCodes.Status500InternalServerError);
}
}
Приставку Set я убрал, т. к. теперь этот метод не задаёт значение, а возвращает.
Соответственно меняем метод Get:
public async IActionResult Get(int id)
{
try
{
...
}
catch (Exception e)
{
LogError(e);
return this.ErrorResponseStatusCode(e);
}
}
Применяем pattern matching и expression body:
public static IActionResult ErrorResponseStatusCode(this ControllerBase controller, Exception exception)
=> exception switch
{
NotImplementedException => new StatusCodeResult(StatusCodes.Status501NotImplemented),
ObjectNotFoundException => controller.NotFound(),
_ => new StatusCodeResult(StatusCodes.Status500InternalServerError)
};