Knocks/BackEnd/Knoks.Test.Integrations/Api/Specification/ApiSpecTest.cs

81 lines
3.8 KiB
C#

//using Knoks.Api.Client;
using Knoks.Api.Controllers.Base;
using Knoks.Core.Entities;
using Knoks.Core.Entities.Args;
using Knoks.Test.Integrations.Api.Tools;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Routing;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Threading.Tasks;
using Xunit;
namespace Knoks.Test.Integrations.Api
{
public class ApiSpecTest : ApiTestClient
{
[Fact(DisplayName = "ApiConsistenceTest")]
void ApiConsistenceTest()
{
var controllerMethods = typeof(ApiBaseController).GetTypeInfo().Assembly.GetTypes()
.Where(type => typeof(ApiBaseController).IsAssignableFrom(type))
.Select(controller => controller.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly)
.Where(m =>
{
if (m.IsSpecialName) return false; //exclude getters and setters
var apiExplorerSettingsAttribute = m.GetCustomAttribute<ApiExplorerSettingsAttribute>();
return (apiExplorerSettingsAttribute == null || !apiExplorerSettingsAttribute.IgnoreApi);
}));
var methods = new List<MethodInfo>();
foreach (var controller in controllerMethods)
foreach (var method in controller)
methods.Add(method);
foreach (var method in methods)
{
Assert.True(method.IsDefined(typeof(HttpMethodAttribute)),
$"The '{nameof(HttpMethodAttribute)}' (GET, POST, PUT) is NOT defined for public {method.DeclaringType.Name}.{method.Name} method.");
foreach (var pi in method.GetParameters())
{
var hasBinding = pi.GetCustomAttributes().Any(a => a is IBindingSourceMetadata);
Assert.True(hasBinding,
$"Paramenter '{pi.Name}' in {method.DeclaringType.Name}.{method.Name} method has NO '{nameof(IBindingSourceMetadata)}' (Form, Body, Route, Query, Header) attributre");
if ((pi.IsDefined(typeof(FromBodyAttribute)) || pi.IsDefined(typeof(FromFormAttribute))) && !typeof(IFormFile).IsAssignableFrom(pi.ParameterType))
Assert.True(typeof(IApiArgs).IsAssignableFrom(pi.ParameterType),
$"Paramenter '{pi.Name} - {pi.ParameterType.Name}' in {method.DeclaringType.Name}.{method.Name} method is NOT implement {nameof(IApiArgs)}");
}
var methodReturnType = method.ReturnType;
var methodReturnTypeInfo = methodReturnType.GetTypeInfo();
if (methodReturnTypeInfo.IsGenericType && methodReturnTypeInfo.GetGenericTypeDefinition() == typeof(Task<>))
methodReturnType = methodReturnType.GenericTypeArguments[0];
Assert.True(typeof(Core.Entities.Interfaces.IApiResult).IsAssignableFrom(methodReturnType)
|| typeof(IActionResult).IsAssignableFrom(methodReturnType),
$"'IApiResult' or 'IActionResult' is not implemented for return type '{methodReturnType.Name}' in {method.DeclaringType}.{method.Name}");
}
}
[Fact(DisplayName = "SwaggerJson")]
async void SwaggerJson()
{
var res = await ApiClient.HttpClient.GetAsync("../spec/v1/swagger.json");
Assert.Equal(HttpStatusCode.OK, res.StatusCode);
var jObject = JsonConvert.DeserializeObject<JObject>(await res.Content.ReadAsStringAsync());
Assert.Equal("2.0", jObject["swagger"].Value<string>());
}
}
}