How to unit test the DataAnnotationsModelBinder in ASP.NET MVC 2
I'm using ASP.NET MVC 2 with DataAnnotation attributes sprinkled on properties like so:
public class LogOnViewModel
{
[Required]
public string UserName { get; set; }
[Required]
public string Password { get; set; }
[Required]
public string Domain { get; set; }
}
I have a unit test which checks that the current view is rendered when validation fails. However, I'm manually adding errors to the ModelState
to get it to work:
[Test]
public void TestThatLogOnActionRedirectsToLogOnViewIfValidationFails()
{
//create a invalid view model
var model = new LogOnViewModel {UserName = "jsmith"};
//Can I avoid doing this manually?
//populate Model State Errors Collection
_accountController.ModelState.AddModelError("FirstName", "First Name Required");
_accountController.ModelState.AddModelError("LastName", "Last Name Required");
var result = _accountController.LogOn(model);
result.AssertViewRendered()
.ForView(Constants.Views.LogOn)
.WithViewData<LogOnViewModel>();
}
Is there a way to interact with the ModelBinder either directly or indirectly in a unit test? For e开发者_StackOverflowxample:
[Test]
public void TestThatLogOnActionRedirectsToLogOnViewIfValidationFails()
{
//create a invalid view model
var model = new LogOnViewModel {UserName = "jsmith"};
//validate model
//not sure about the api call...
var validationResults = new DataAnnotationsModelBinder().Validate(model);
_accountController.ModelState.Merge(validationResults);
var result = _accountController.LogOn(model);
result.AssertViewRendered()
.ForView(Constants.Views.LogOn)
.WithViewData<LogOnViewModel>();
}
Brad Wilson has a nice blogpost about the DataAnnotationsModelBinder, including how to unit test it: http://bradwilson.typepad.com/blog/2009/04/dataannotations-and-aspnet-mvc.html
I usually unit test my model validation setup by directly calling the facade methods of System.ComponentModel.DataAnnotations.Validator.
I wrote a article on the subject http://timoch.com/blog/2013/06/unit-testing-model-validation-with-mvcs-dataannotations/
I end up with code like this (the article show a cleaner and reusable unit test base class for model validation)
[Test]
[TestCaseSource("ValidationRule_Source")]
public void ValidationRule(ValidateRuleSpec spec) {
// Arrange
var model = CreateValidPersonModel();
// Apply bad valud
model.GetType().GetProperty(spec.MemberName).SetValue(model, spec.BadValue);
// Act
var validationResults = new List<ValidationResult>();
var success = Validator.TryValidateObject(model, new ValidationContext(model), validationResults, true);
// Assert
Expect(success, False);
Expect(validationResults.Count, EqualTo(1));
Expect(validationResults.SingleOrDefault(r => r.MemberNames.Contains(spec.MemberName)), Not.Null);
}
public IEnumerable<ValidateRuleSpec> ValidationRule_Source() {
yield return new ValidateRuleSpec() {
BadValue = null,
MemberName = "FirstName"
};
yield return new ValidateRuleSpec() {
BadValue = string.Empty,
MemberName = "FirstName"
};
yield return new ValidateRuleSpec() {
BadValue = null,
MemberName = "LastName"
};
/* ... */
}
I don't like trusting code to just work so I systematically write unit test for my model validation code. However, I do trust the framework/model binder to execute validation. This unit test allows me to write controller that trust the validation is OK.
精彩评论