I have the following attribute:
public class ValidateModelAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (actionContext.ModelState.IsValid == false)
{
actionContext.Response = actionContext.Request.CreateErrorResponse(
HttpStatusCode.BadRequest, actionContext.ModelState);
}
}
}
I have this generic extension method for Determining whether the attribute is applied to a method or not
public static bool ActionHasFilter(this ApiController controller, string action, Type filter)
{
var controllerType = controller.GetType();
var method = controllerType.GetMethod(action);
object[] filters = method.GetCustomAttributes(filter, true);
return filters.Any(x=>x.GetType() == filter);
}
My problem is how do i go about testing whether the attribute actually works or not, without testing the controller action?
Let's say i have the following Entity
public class UserViewModel
{
[Required]
public string Name {get; set;}
[Required]
[EmailAddress]
public string Email {get;set;
}
How would i go about mocking the context and checking whether the model is valid?
I'm using Nunit and Moq.
Spock's solution is on the right track, but is a bit too invasive on the code, because it makes the ValidateModelAttribute
class dependent on TestableHttpActionContext
. My implementation uses a public property that will be used to "inject" the Request
object for the Unit Tests, while the implementation as attribute continues to use the Request
object from the ActionContext
:
public class ValidateModelAttribute : ActionFilterAttribute
{
public HttpRequestMessage TestRequestMessage { get; set; }
public override void OnActionExecuting(HttpActionContext actionContext)
{
PerformValidation(actionContext, TestRequestMessage ?? actionContext.Request);
}
private void PerformValidation(HttpActionContext actionContext, HttpRequestMessage request)
{
if (actionContext.ModelState.IsValid == false)
{
actionContext.Response = request.CreateErrorResponse(HttpStatusCode.BadRequest, actionContext.ModelState);
}
}
}
Unit tests:
[Test]
public void OnActionExecuting_ValidModel_ResponseIsNotSet()
{
var actionContext = new HttpActionContext();
actionContext.ModelState.Clear();
var attribute = new ValidateModelAttribute { TestRequestMessage = new HttpRequestMessage() };
attribute.OnActionExecuting(actionContext);
Assert.IsNull(actionContext.Response);
}
[Test]
public void OnActionExecuting_InvalidModel_ResponseIsSetToBadRequest()
{
var actionContext = new HttpActionContext();
actionContext.ModelState.AddModelError("key", "error");
var attribute = new ValidateModelAttribute() { TestRequestMessage = new HttpRequestMessage() };
attribute.OnActionExecuting(actionContext);
Assert.AreEqual(HttpStatusCode.BadRequest, actionContext.Response.StatusCode);
}
Please note that I'm not using an actual model to validate the ModelState
, because that's out of scope for the Unit Tests: We want to test the ModelState
's outcome, not the ModelState
itself. ;-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With