Skip to content

Instantly share code, notes, and snippets.

@tathamoddie
Created December 14, 2012 03:18
Show Gist options
  • Save tathamoddie/4282432 to your computer and use it in GitHub Desktop.
Save tathamoddie/4282432 to your computer and use it in GitHub Desktop.
Some common unit tests that I like to apply to ASP.NET MVC projects
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Security.Permissions;
using System.Web.Mvc;
using Example.Web;
using NUnit.Framework;
namespace Example.UnitTests.Web
{
[TestFixture]
public class ActionTests
{
[Test]
[TestCaseSource(typeof(AllMvcActions), "GetActions")]
public void AllActionsShouldBeExplicitlyGetOrPost(MethodInfo action)
{
if (action.GetCustomAttributes(typeof (ChildActionOnlyAttribute), false).Any() ||
action.GetCustomAttributes(typeof (HttpDeleteAttribute), false).Any() ||
action.GetCustomAttributes(typeof (HttpGetAttribute), false).Any() ||
action.GetCustomAttributes(typeof (HttpPostAttribute), false).Any() ||
action.GetCustomAttributes(typeof (HttpPutAttribute), false).Any())
return;
if (action.DeclaringType == null)
throw new InvalidOperationException("An assumption about reflection was just proven wrong: action.DeclaringType was null. Test failed (method may or may not actually be correct).");
Assert.Fail("{0}.{1} is missing one of [ChildActionOnly], [HttpDelete], [HttpGet], [HttpPut] or [HttpPost]", action.DeclaringType.Name, action.Name);
}
[Test]
[TestCaseSource(typeof(AllMvcActions), "GetActions")]
public void AllMutatingActionsShouldHaveAntiForgeryValidation(MethodInfo action)
{
var isMutatingAction =
action.GetCustomAttributes(typeof(HttpDeleteAttribute), false).Any() ||
action.GetCustomAttributes(typeof(HttpPutAttribute), false).Any() ||
action.GetCustomAttributes(typeof(HttpPostAttribute), false).Any();
if (!isMutatingAction)
return;
if (action.GetCustomAttributes(typeof(ValidateAntiForgeryTokenAttribute), false).Any())
return;
if (action.DeclaringType == null)
throw new InvalidOperationException("An assumption about reflection was just proven wrong: action.DeclaringType was null. Test failed (method may or may not actually be correct).");
Assert.Fail("{0}.{1} is marked with [HttpDelete], [HttpPut] or [HttpPost] but missing [ValidateAntiForgeryToken]", action.DeclaringType.Name, action.Name);
}
[Test]
[TestCaseSource(typeof(AllMvcActions), "GetActions")]
public void AllMutatingActionsShouldHaveAuthorizeOrAllowAnonymous(MethodInfo action)
{
var isMutatingAction =
action.GetCustomAttributes(typeof(HttpDeleteAttribute), false).Any() ||
action.GetCustomAttributes(typeof(HttpPutAttribute), false).Any() ||
action.GetCustomAttributes(typeof(HttpPostAttribute), false).Any();
if (!isMutatingAction)
return;
if (action.GetCustomAttributes(typeof(AuthorizeAttribute), false).Any() ||
action.GetCustomAttributes(typeof(AllowAnonymousAttribute), false).Any())
return;
if (action.DeclaringType == null)
throw new InvalidOperationException("An assumption about reflection was just proven wrong: action.DeclaringType was null. Test failed (method may or may not actually be correct).");
Assert.Fail("{0}.{1} is marked with [HttpDelete], [HttpPut] or [HttpPost] but missing either [Authorize] or [AllowAnonymous]", action.DeclaringType.Name, action.Name);
}
[Test]
[TestCaseSource(typeof(AllMvcActions), "GetActions")]
public void AllAuthorizeActionsShouldHavePrincipalPermissionAttribute(MethodInfo action)
{
if (!action.GetCustomAttributes(typeof(AuthorizeAttribute), false).Any())
return;
if (action.GetCustomAttributes(typeof(PrincipalPermissionAttribute), false).Any())
return;
if (action.DeclaringType == null)
throw new InvalidOperationException("An assumption about reflection was just proven wrong: action.DeclaringType was null. Test failed (method may or may not actually be correct).");
Assert.Fail("{0}.{1} is marked with [Authorize] but missing [PrincipalPermission(SecurityAction.Demand, Role=UserRoles.Something)]. You should be explicit about which roles are allowed to call something.", action.DeclaringType.Name, action.Name);
}
public class AllMvcActions
{
public IEnumerable<MethodInfo> GetActions()
{
var controllers = typeof(MvcApplication)
.Assembly
.GetTypes()
.Where(t => typeof(Controller).IsAssignableFrom(t));
var actions = controllers
.SelectMany(c => c.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly))
.Where(m => !m.IsSpecialName);
return actions;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment