Sprint 8 #43
136
MainProject.Tests/Core/Filters/ValidationActionFilter_Tests.cs
Normal file
136
MainProject.Tests/Core/Filters/ValidationActionFilter_Tests.cs
Normal file
@@ -0,0 +1,136 @@
|
||||
using BasicDotnetTemplate.MainProject.Models.Api.Common.User;
|
||||
using DatabaseSqlServer = BasicDotnetTemplate.MainProject.Models.Database.SqlServer;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using BasicDotnetTemplate.MainProject.Models.Settings;
|
||||
using BasicDotnetTemplate.MainProject.Utils;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using BasicDotnetTemplate.MainProject.Core.Attributes;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Moq;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc.Controllers;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using BasicDotnetTemplate.MainProject.Core.Filters;
|
||||
using Newtonsoft.Json;
|
||||
using BasicDotnetTemplate.MainProject.Models.Api.Base;
|
||||
|
||||
|
||||
namespace BasicDotnetTemplate.MainProject.Tests;
|
||||
|
||||
[TestClass]
|
||||
public class ValidationActionFilter_Tests
|
||||
{
|
||||
private readonly string _requestNotWellFormedMessage = "Request is not well formed";
|
||||
|
||||
private static ActionExecutingContext CreateContext(ModelStateDictionary modelState, object? requestBody = null)
|
||||
{
|
||||
var actionContext = new ActionContext(
|
||||
new DefaultHttpContext(),
|
||||
new Microsoft.AspNetCore.Routing.RouteData(),
|
||||
new Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor(),
|
||||
modelState
|
||||
);
|
||||
var actionArguments = new Dictionary<string, object?>();
|
||||
|
||||
if (requestBody != null)
|
||||
{
|
||||
actionArguments.Add("request", requestBody);
|
||||
}
|
||||
return new ActionExecutingContext(
|
||||
actionContext,
|
||||
[],
|
||||
actionArguments,
|
||||
new Mock<Controller>().Object
|
||||
);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void OnActionExecutionAsync_ModelStateInvalid_ReturnsBadRequestAndDoesNotCallNext()
|
||||
{
|
||||
// Arrange
|
||||
var modelState = new ModelStateDictionary();
|
||||
modelState.AddModelError("MissingProperty", "MissingProperty is required");
|
||||
var context = CreateContext(modelState, new { SomeProp = "Value" });
|
||||
var nextCalled = false;
|
||||
ActionExecutionDelegate next = () => {
|
||||
nextCalled = true;
|
||||
return Task.FromResult(new ActionExecutedContext(context, [], new Mock<Controller>().Object));
|
||||
};
|
||||
var filter = new ValidationActionFilter();
|
||||
// Act
|
||||
filter.OnActionExecutionAsync(context, next).GetAwaiter().GetResult();
|
||||
// Assert
|
||||
Assert.IsNotNull(context.Result);
|
||||
var badRequestResult = context.Result as BadRequestObjectResult;
|
||||
Assert.IsNotNull(badRequestResult);
|
||||
Assert.IsNotNull(badRequestResult!.Value);
|
||||
|
||||
ValidationError validationError = (ValidationError)badRequestResult.Value;
|
||||
Assert.AreEqual(_requestNotWellFormedMessage, validationError?.Message);
|
||||
Assert.IsNotNull(validationError?.Errors);
|
||||
Assert.IsFalse(modelState.IsValid);
|
||||
Assert.IsFalse(nextCalled);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void OnActionExecutionAsync_ModelStateValid_RequestBodyNull_ReturnsBadRequestAndDoesNotCallNext()
|
||||
{
|
||||
|
||||
var modelState = new ModelStateDictionary();
|
||||
|
||||
var context = CreateContext(modelState, null);
|
||||
var nextCalled = false;
|
||||
ActionExecutionDelegate next = () => {
|
||||
nextCalled = true;
|
||||
return Task.FromResult(new ActionExecutedContext(context, [], new Mock<Controller>().Object));
|
||||
};
|
||||
var filter = new ValidationActionFilter();
|
||||
// Act
|
||||
filter.OnActionExecutionAsync(context, next).GetAwaiter().GetResult();
|
||||
// Assert
|
||||
Assert.IsNotNull(context.Result);
|
||||
var badRequestResult = context.Result as BadRequestObjectResult;
|
||||
Assert.IsNotNull(badRequestResult);
|
||||
Assert.IsNotNull(badRequestResult!.Value);
|
||||
|
||||
ValidationError validationError = (ValidationError)badRequestResult.Value;
|
||||
Console.WriteLine(JsonConvert.SerializeObject(validationError));
|
||||
Assert.AreEqual(_requestNotWellFormedMessage, validationError?.Message);
|
||||
Assert.IsNull(validationError?.Errors);
|
||||
Assert.IsTrue(modelState.IsValid);
|
||||
Assert.IsFalse(nextCalled);
|
||||
}
|
||||
|
||||
|
||||
[TestMethod]
|
||||
public void OnActionExecutionAsync_ModelStateValid_RequestBodyValid_CallsNextAndDoesNotSetResult()
|
||||
{
|
||||
// Arrange
|
||||
var modelState = new ModelStateDictionary();
|
||||
|
||||
var requestBody = new TestRequestBody { Value = "Test" };
|
||||
var context = CreateContext(modelState, requestBody);
|
||||
var nextCalled = false;
|
||||
ActionExecutionDelegate next = () => {
|
||||
nextCalled = true;
|
||||
return Task.FromResult(new ActionExecutedContext(context, [], new Mock<Controller>().Object));
|
||||
};
|
||||
var filter = new ValidationActionFilter();
|
||||
// Act
|
||||
filter.OnActionExecutionAsync(context, next).GetAwaiter().GetResult();
|
||||
// Assert
|
||||
Assert.IsNull(context.Result);
|
||||
Assert.IsTrue(nextCalled);
|
||||
}
|
||||
|
||||
|
||||
private class TestRequestBody
|
||||
{
|
||||
public string? Value { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using BasicDotnetTemplate.MainProject.Models.Api.Base;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using System.Threading.Tasks;
|
||||
@@ -12,15 +13,27 @@ namespace BasicDotnetTemplate.MainProject.Core.Filters
|
||||
{
|
||||
if (!context.ModelState.IsValid)
|
||||
{
|
||||
context.Result = new BadRequestObjectResult(new { message = _requestNotWellFormedMessage, errors = context.ModelState });
|
||||
context.Result = new BadRequestObjectResult(new ValidationError
|
||||
{
|
||||
Message = _requestNotWellFormedMessage,
|
||||
Errors = context.ModelState.Where(m =>
|
||||
m.Value != null && m.Value.Errors.Any())
|
||||
.ToDictionary(
|
||||
m => m.Key,
|
||||
m => m.Value!.Errors.Select(e => e.ErrorMessage).ToList()
|
||||
)
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var requestBody = context.ActionArguments.Values.FirstOrDefault(arg => arg != null && !arg.GetType().IsPrimitive && !(arg is string));
|
||||
var requestBody = context.ActionArguments.Values.FirstOrDefault(arg => arg != null && !arg.GetType().IsPrimitive && arg is not string);
|
||||
|
||||
if (requestBody == null)
|
||||
{
|
||||
context.Result = new BadRequestObjectResult(new { message = _requestNotWellFormedMessage });
|
||||
context.Result = new BadRequestObjectResult(new ValidationError
|
||||
{
|
||||
Message = _requestNotWellFormedMessage
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
9
MainProject/Models/Api/Base/ValidationError.cs
Normal file
9
MainProject/Models/Api/Base/ValidationError.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace BasicDotnetTemplate.MainProject.Models.Api.Base;
|
||||
|
||||
public class ValidationError
|
||||
{
|
||||
public string Message { get; set; }
|
||||
public Dictionary<string, List<string>> Errors { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user