What's the best way of going about testing model validation without making assumptions on the implementation details of the validation (eg. DataAnnotations).
For example, if I have a Customer model object that has a Firstname property, I want to test that binding a missing value for the Firstname property will result in a validation error but I don't want to test how validation his been implemented. That is, I don't want to use DataAnotations.Validate.
I've seen several, differing, opinions on this floating around and haven't found one that I agree with.
I ended up writing a helper method that wraps ModelValidator and returns IEnumerable<ModelValidationResult>. It requires that MVC be configured with your validation provider of choice, but it means that test code need not change when your validation implementation does:
public static IEnumerable<ModelValidationResult> Validate<TModel>(TModel model)
{
var modelMetadata = ModelMetadata.FromLambdaExpression(r => r,
new ViewDataDictionary<TModel>(model));
ModelValidator validator = ModelValidator.GetModelValidator(
modelMetadata, new ControllerContext());
return validator.Validate(model);
}
This will depend on the framework you are using for validating your models. So what you are asking is not possible without taking this into account. ASP.NET MVC by default uses a data annotations model provider which invokes the validation rules for data annotations and if you want to test this you will need to do a DataAnnotations.Validate in your unit tests or verify that your model is decorated with the proper attributes.
Personally I use FluentValidation.NET which provides an elegant way for unit testing my validators so it is not much of a hassle.
Related
I'm participating in a project using ASP.NET MVC 3 and DataAnnotations. We have DataAnnotations in ViewModels classes.
How do you write unit tests for these validations?
ViewModel example:
public class AchievementVM
{
[Required(ErrorMessage = "The title field is required.")]
[StringLength(100, ErrorMessage = "Title must be 100 characters or less.")]
public string Title { get; set; }
}
Thanks!
The .NET framework comes with a Validator class which can exercise your validation logic in isolation. The code to test could look like this:
var achievement = new AchievementVM();
var context = new ValidationContext(achievement,
serviceProvider: null, items: null);
var results = new List<ValidationResult>();
var isValid = Validator.TryValidateObject(achievement, context, results, true);
Assert.IsTrue(results.Any(vr => vr.ErrorMessage == "The title field is required."));
achievement.Title = "Really really long title that violates "
+ "the range constraint and should not be accepted as "
+ "valid input if this has been done correctly.";
Validator.TryValidateObject(achievement, context, results, true);
Assert.IsTrue(results.Any(vr => vr.ErrorMessage == "Title must be 100 characters or less."));
No need for custom utilities to search for the existance of attributes. The Validator class does the work for you and populates a ValidationResult collection the same as the MVC infrastructure.
A good writeup on this method can be found on K. Scott Allen's blog.
Since those annotations are very declarative, there is little sense in writing unit tests which just check (with reflection) that the methods are annotated - the tests would just be duplicating the production code. And that would still leave the possibility that the annotations are not being used the way that the framework expects them to be used (maybe they are the wrong annotations, they are in the wrong place, or they are missing some additional configuration).
Thus a meaningful test would not be a unit test, but an integration test which makes sure that the system is detecting the annotations correctly. To keep the speed reasonable, try to make those integration tests as focused as possible, by instantiating as little of the framework as possible (which requires deep knowledge of the framework - RTFS). If nothing else, an end-to-end test could check the correct use of the annotations by parsing the HTML and checking that the validation errors are shown when invalid data is entered into the fields.
It should be necessary to write just a couple of integration/end-to-end tests to make sure that validation has been enabled. There shouldn't be need to test each and every field, when they all work the same way.
See here: Unit Testing ASP.NET DataAnnotations validation
Also, you can use reflection to see if a property of class has any necessary attribute or not.
After a year or so of MVC experience I'm still confused about one thing: How to effectively use the DataAnnotations with ModelState.IsValid? For simple tutorial example this all works just fine and I have no questions about that. But supposed I have the following model:
Public Class Movie
Public Property MovieID As Integer
Public Property Title As String
Public Property Year As Integer
Public Property AddedByUser As String
End Class
Now the field AddedByUser is required in the database however I don't want the user to provide this but rather the business logic based on the currently logged in user. How would I use the DataAnnotation attributes for this scenario? If I make this field required then in the controller when I say:
Public Function SaveMovie(ByVal entity as Movie) As ActionResult
If ModelState.IsValid
// Save to DB here...
End If
Return View(entity)
End Function
... the validation will fail because I don't have that field in the view bindings. Should I have a hidden field for this? Should I write a custom view model for SaveMovie action? I suppose I could write my own validation in business logic but then why use model validation at all? Custom model binder perhaps? What is the best way to handle these types of scenarios?
Just to give another example scenario what about the difference between insert and update operation and validation? For update operations object's primary key is required. However that is not the case for inserts. Are you supposed to have separate models for insert and update just because of this one key property?
so the way that I handle this is I use the DataAnnotation based validation for user input type stuff. i.e. Validation on email addresses, dates, required fields etc. Stuff that you need a quick 'sanity check' on and need to double check the users entries on.
I don't put any DataAnnotations on the fields that my Database controls or my code controls, i.e. Primary Keys, your [AddedByUser] property as the user doesn't access these properties directly and so you shouldn't have to add validation checks on this. Since your code is the only thing that updates these properties, why validate them?
For more 'business rule' type validation I implement IValidatableObject on my model which gets run, in MVC, after all property-level validations have succeeded. Note that it won't run if the property-level validations fail. And this makes sense, because if the data is 'dirty' you wouldn't want to proceed to run more complex validation etc.
Hope this helps :)
This question title is likely to be worded poorly so feel free to adjust.
In my MVC application I have a custom attribute which i use to decorate email fields which then either passes or fails the model.
On one pge though I allow the use to submit a comment but I submit via ajax and so do not do a full postback and no model validation.
So I'd like to validate the address but not copy the code. I'd also like to avoid breaking the code out of the validator into yet another class or is this the best wAY?
Is there another way? Can I create the model in the ajax postback and validate it there and then return the partial view with the error messages?
Or is there another way?
You say, ...
So I'd like to validate the address but not copy the code. I'd also like to avoid breaking the code out of the validator into yet another class or is this the best way?
IMO, that is the best way. Factor out the common code. I see your issue though, our EmailValidator inherits from RegularExpressionValidator, so it's hard to factor out. We have a RegEx utility class that uses the same RegEx pattern. We refer to the pattern by constant in both places...
public class EmailAttribute : RegularExpressionAttribute
{
public EmailAttribute() :
base(RegExUtility.SingleEmailAddressPattern)
{
ErrorMessage = "Please enter a valid email address";
}
and
public static class RegExUtility
{
public const SingleEmailAddressPattern = #"...";
public static bool IsValidSingleEmailAddress(string email)
{
return Regex.IsMatch(email, SingleEmailAddressPattern);
For simple Ajax postback actions, I think you can often handle it in the controller or create a separate POCO ViewModel that just supports the Ajax path. I know there are articles on using the same model for both types of actions, but we've found there are usually enough differences that it's worth having separate view models. If they're complex enough, we just factor out the common code.
Here is the lay of the land. Like most people I have my domain object and I have my view models. I love the idea of using view models, as it allows for models to be created specifically for a given view context, without needing to alter my business objects.
The problem I have is with type level validation defined on my domain object and getting those rules to the client. In this case lets say I am using data annotations to describe the validation rules, when I move the data from the domain object to the view model, the view model no longer knows what validation it should get the interface to perform (because the validation is defined back on the domain object).
With MVC 2 you can get it to automatically perform client/server side validation, based on the validation rules of the current object. But because the validation rules are defined on the domain object and not the view model, I would have to duplicate the validation rules on the view model to get this to work.
How do others deal with this type of issue? My thinking is that besides mapping the data from the domain object to the view model, we also need to map across the validation rules, but I haven't really seen others talking about this issue... Brad Wilson has recently talked about this issue at length but hasn't really addressed the duplication of rules on the domain object and on the view models... what are your thoughts?
Cheers
Anthony
The DataAnnotation attributes are about validating input and giving UI feedback to the end user. That's really their only intended use. I use different validation strategies for UI objects and business objects, so the DA validation attributes only end up on models being shown to the user.
This may not be appropriate, but what if you just moved your validation rules/annotations from your Models to your ViewModels? In a few of the projects I've been on, we've chosen to prevent the View from accessing anything but information exposed through its corresponding ViewModel. Since all data interaction would be performed through the ViewModel, there wouldn't be a need to have validation on your Model objects.
The counter to this argument is that you could easily duplicate certain validation rules, since different ViewModels might be interfacing with the same Models. In this case, it might make sense to simply declare your Model as a property exposed on your ViewModel. For postbacks, they could accept a Model as their parameter, allowing the ModelBinder infrastructure to handle the request. In this case, if ModelState.IsValid is false, you could just reassign the property to your ViewModel before redisplaying the View.
I would recommend moving your annotations to your ViewModels. It makes sense since a lot of Views are a) the result of composition of several models or b) a subset of model data.
It turns out that AutoMapper may be able to do this for us automagically, which is the best case scenario.
AutoMapper-users: Transfer validation attributes to the viewmodel?
http://groups.google.com/group/automapper-users/browse_thread/thread/efa1d551e498311c/db4e7f6c93a77302?lnk=gst&q=validation#db4e7f6c93a77302
I haven't got around to trying out the proposed solutions there, but intend to shortly.
(Cross posted this on my (dupe) question as well).
Probably we shouldn't use view models at all?
And define validation rules on model layer entities..
I've been considering this as well for a while now. I totally understand Brad's reply. However, let's assume I want to use another validation framework that is suitable for annotating both domain entities and view models.
The only solution I can come up with on paper that still works with attributes would be to create another attribute that "points" to a domain entity's property that you are mirroring in your view model. Here's an example:
// In UI as a view model.
public class UserRegistration {
[ValidationDependency<Person>(x => x.FirstName)]
public string FirstName { get; set; }
[ValidationDependency<Person>(x => x.LastName)]
public string LastName { get; set; }
[ValidationDependency<Membership>(x => x.Username)]
public string Username { get; set; }
[ValidationDependency<Membership>(x => x.Password)]
public string Password { get; set; }
}
A framework like xVal could possibly be extended to handle this new attribute and run the validation attributes on the dependency class' property, but with your view model's property value. I just haven't had time to flesh this out more.
Any thoughts?
I'm using the Data Annotation validation extensively in ASP.NET MVC 2. This new feature has been a huge time saver, as I'm now able to define both client-side validation and server-side validation in one place. However, while I was doing some detailed testing, I realized that it's quite easy for someone to bypass the server-side validation if I relied on Data Annotation validation alone. For example, if I defined a required field by annotating the property with the [Required] attribute and placed a textbox for that required field in a form, a user could simply remove the textbox from the DOM (which can easily be done through Firebug) and now the Data Annotation validation will not be triggered on that property during ModelBinding inside of a Controller. To ensure that the "required" validation is triggered, I can repeat the validation after ModelBinding happens, but then I'd be repeating my validation logic.
What is everyone's recommendation on validation? Is Data Annotation validation enough? Or does the validation need to be repeated to ensure that validations get triggered in all situations?
Follow-up comment:
Based on the answers below, it seems that I can't rely on the Model Binder and Data Annotation validation alone. Since we're concluding that additional server-side validation is required, is there an easy way for my Service layer to trigger validation based on what's been defined in the Data Annotations? It seems that this will get us the best of both words...we won't need to repeat the validation code, but we'll still ensure that the validation gets executed even if Model Binder doesn't trigger it.
I'm going to post this follow-up comment as a separate question, as it poses a different question than the original one.
I think to be vigilant concerning security you should choose to you make server validation the priority and ensure that this is always your fallback. Your server validation should work without the client validation. Client validation is more for UX and tho that is paramount to your design, it is secondary to security. With this in mind you will find yourself repeating your validation. A goal is often trying to design your app so that the server and client validation can be integrated as much as possible to reduce the work required to validate on the server and the client. But be assured you must do both.
If bypassing the client validation (by means of DOM manipulation) is avoiding the server validation (which it seems you are indicating) then your server validation for this instance may not be employed appropriately. You should be invoking your server validation again in your controller action or in a service layer. The scenario you describe should not be defeating your server validation.
With the scenario you describe, the DataAnnotation attributes method should be sufficient. It seems that you simply need to make a few code changes to ensure that your server validation is invoked also when submitting the form.
I paired xVal with DataAnnotations and have written my own Action filter that checks any Entity type parameters for validation purposes. So if some field is missing in the postback, this validator will fill ModelState dictionary hence having model invalid.
Prerequisites:
my entity/model objects all implement IObjectValidator interface which declares Validate() method.
my attribute class is called ValidateBusinessObjectAttribute
xVal validation library
Action filter code:
public void OnActionExecuting(ActionExecutingContext filterContext)
{
IEnumerable<KeyValuePair<string, object>> parameters = filterContext.ActionParameters.Where<KeyValuePair<string, object>>(p => p.Value.GetType().Equals(this.ObjectType ?? p.Value.GetType()) && p.Value is IObjectValidator);
foreach (KeyValuePair<string, object> param in parameters)
{
object value;
if ((value = param.Value) != null)
{
IEnumerable<ErrorInfo> errors = ((IObjectValidator)value).Validate();
if (errors.Any())
{
new RulesException(errors).AddModelStateErrors(filterContext.Controller.ViewData.ModelState, param.Key);
}
}
}
}
My controller action is defined like this then:
[ValidateBusinessObject]
public ActionResult Register(User user, Company company, RegistrationData registrationData)
{
if (!this.ModelState.IsValid)
{
return View();
}
...
}
The DataAnnotation is certainly not enough. I use it extensively also to pre-validate my calls to the domain model to get better error reporting and fail as early as possible.
You can however tweak the DataAnnotation Model yourself to ensure properties with [Required] MUST be posted. (will follow up with code later today).
UPDATE
Get the source for DataAnnotations Model Binder and find this line in DataAnnotationsModelBinder.cs
// Only bind properties that are part of the request
if (bindingContext.ValueProvider.DoesAnyKeyHavePrefix(fullPropertyKey)) {
Change it to
// Only bind properties that are part of the request
bool contextHasKey = bindingContext.ValueProvider.DoesAnyKeyHavePrefix(fullPropertyKey);
bool isRequired = GetValidationAttributes(propertyDescriptor).OfType<RequiredAttribute>().Count() > 0;
if (contextHasKey || (!contextHasKey && isRequired)) {
I wrote my own ValidationService for MVC 1.0 by copying patterns from both xVal's DataAnnotationsRuleProvider and Microsoft's DataAnnotationsModelBinder (and Martijn's comments). The service interface is below:
public interface IValidationService
{
void Validate(object instance);
IEnumerable<ErrorInfo> GetErrors(object instance);
}
public abstract class BaseValidationService : IValidationService
{
public void Validate(object instance)
{
var errors = GetErrors(instance);
if (errors.Any())
throw new RulesException(errors);
}
public abstract IEnumerable<ErrorInfo> GetErrors(object instance);
}
The service is a validation runner that walks the property tree of the object instance it receives and actually executes the validation attributes that it finds on each property, building a list of ErrorInfo objects when attributes are not valid. (I'd post the whole source but it was written for a client and I don't know yet if I'm authorized to do so.)
You can then have your controllers, business logic services explicitly invoke validation when you are ready, rather than relying exclusively on the model binder for validation.
There are a couple of other pitfalls that you should be aware of:
The default DataTypeAttribute in data
annotations doesn't actually do any
data type validation, so you'll need
to write a new attribute that
actually uses xVal regular
expressions (or something else) to
perform server-side data type
validation.
xVal doesn't walk
properties to create client-side
validation, so you may want to make
some changes there to get more robust
client-side validation.
If I am allowed and have time, I will try to make more source available...
See codeProject Server-side Input Validation using Data Annotations
Input validation can be done automatically on the client side in
ASP.NET MVC or explicitly validating the model against the rules. This
tip will describe how it can be done manually on the server-side of an
ASP.NET applications or within the repository code of WPF
applications.
// Use the ValidationContext to validate the Product model against the product data annotations
// before saving it to the database
var validationContext = new ValidationContext(productViewModel, serviceProvider: null, items:null);
var validationResults = new List<ValidationResult>();
var isValid = Validator.TryValidateObject(productViewModel, validationContext,validationResults, true);