Last active
June 6, 2020 11:26
-
-
Save AMCN41R/7331c282a60c46f1b9ee5a0fc0933d9a to your computer and use it in GitHub Desktop.
C# Controller Unit Test Assertion Helpers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace TestHelpers | |
{ | |
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using Microsoft.AspNetCore.Mvc; | |
using Microsoft.AspNetCore.Mvc.Routing; | |
/// <summary> | |
/// A set of methods to aid C# Controller unit test assertions. | |
/// </summary> | |
public static class AssertController | |
{ | |
/// <summary> | |
/// Verifies that a controller has the <see cref="RouteAttribute"/> with the correct template. | |
/// </summary> | |
/// <typeparam name="TController">The controller to verify.</typeparam> | |
/// <param name="route">The expected route.</param> | |
public static void HasRouteAttribute<TController>(string route) | |
where TController : ControllerBase | |
{ | |
var attr = typeof(TController).GetCustomAttributes(typeof(RouteAttribute), false).ToList(); | |
attr.AssertAttributeCount<RouteAttribute>(); | |
Xunit.Assert.Equal(route.ToLower(), ((RouteAttribute)attr[0]).Template.ToLower()); | |
} | |
/// <summary> | |
/// Verifies that a controller method has the correct <see cref="HttpMethodAttribute"/>. | |
/// </summary> | |
/// <typeparam name="TController">The controller that contains the method to verify.</typeparam> | |
/// <typeparam name="TVerbAttribute">The expected verb attribute.</typeparam> | |
/// <param name="methodName">The name of the method to verify.</param> | |
public static void MethodHasVerb<TController, TVerbAttribute>(string methodName) | |
where TController : ControllerBase | |
where TVerbAttribute : HttpMethodAttribute | |
{ | |
var method = typeof(TController).GetMethod(methodName); | |
var attr = method?.GetCustomAttributes(typeof(TVerbAttribute), false).ToList(); | |
attr.AssertAttributeCount<TVerbAttribute>(); | |
} | |
/// <summary> | |
/// Verifies that a controller method has the correct <see cref="HttpMethodAttribute"/> with the correct route template. | |
/// </summary> | |
/// <typeparam name="TController">The controller that contains the method to verify.</typeparam> | |
/// <typeparam name="TVerbAttribute">The expected verb attribute.</typeparam> | |
/// <param name="methodName">The name of the method to verify.</param> | |
/// <param name="template">The expected route template.</param> | |
public static void MethodHasVerb<TController, TVerbAttribute>(string methodName, string template) | |
where TController : ControllerBase | |
where TVerbAttribute : HttpMethodAttribute | |
{ | |
var method = typeof(TController).GetMethod(methodName); | |
var attr = method?.GetCustomAttributes(typeof(TVerbAttribute), false).ToList(); | |
if (attr == null) | |
{ | |
throw new Exception("No custom attributes found."); | |
} | |
attr.AssertAttributeCount<TVerbAttribute>(); | |
var verb = (HttpMethodAttribute)attr[0]; | |
Xunit.Assert.Equal(template, verb.Template); | |
} | |
private static void AssertAttributeCount<T>(this ICollection<object> attr) | |
where T : Attribute | |
{ | |
var baseMessage = $"Assert has {typeof(T).Name} attribute failure."; | |
if (attr.Count == 0) | |
{ | |
throw new Exception($"{baseMessage} No such attribute."); | |
} | |
if (attr.Count > 1) | |
{ | |
throw new Exception( | |
$"{baseMessage} Attribute should exist once but exists {attr.Count} times."); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[Route("api/orders")] | |
public class OrderController : ControllerBase | |
{ | |
[HttpGet] | |
public async Task<IActionResult> GetOrders() | |
{ | |
// implementation | |
} | |
[HttpGet("{orderId}/products")] | |
public async Task<IActionResult> GetProductsForOrder(Guid orderId) | |
{ | |
// implementation | |
} | |
} | |
public class OrderControllerTests | |
{ | |
[Fact] | |
public void Controller_RouteAttribute_IsPresentWIthCorrectRoute() | |
{ | |
AssertController.HasRouteAttribute<OrderController>("api/orders"); | |
} | |
[Fact] | |
public void GetOrders_Method_HasCorrectVerbAttribute() | |
{ | |
AssertController | |
.MethodHasVerb<OrderController, HttpGetAttribute>( | |
nameof(OrderController.GetOrders) | |
); | |
} | |
[Fact] | |
public void GetProductsForOrder_Method_HasCorrectVerbAttributeAndPath() | |
{ | |
AssertController | |
.MethodHasVerb<OrderController, HttpGetAttribute>( | |
nameof(OrderController.GetProductsForOrder), | |
"{orderId}/products" | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment