c# - ejemplo - unit test dotnet
ASP.NET MVC Controller prueba de unidad posterior al método: ModelState.IsValid siempre verdadero (2)
Encontré esta solución: SO: La validación no funciona cuando uso Validator.TryValidateObject combinado con la solución que proporcionó @Kenneth:
[TestMethod]
public void test_validation()
{
var sut = new POSViewModel();
// Set some properties here
var context = new ValidationContext(sut, null, null);
var results = new List<ValidationResult>();
TypeDescriptor.AddProviderTransparent(new AssociatedMetadataTypeTypeDescriptionProvider(typeof(POSViewModel), typeof(POSViewModel)), typeof(POSViewModel));
var isModelStateValid = Validator.TryValidateObject(sut, context, results, true);
// Assert here
}
Si tiene una biblioteca de clases con todos sus recursos, no olvide consultarla en su proyecto de prueba.
He escrito mis primeras pruebas unitarias para una aplicación web ASP.NET MVC. Todo funciona bien y me está dando información valiosa, pero no puedo probar errores en el modelo de vista. ModelState.IsValid siempre es verdadero, incluso cuando algunos valores no se completan (cadena vacía o nula).
Ya leí que la validación del modelo ocurre cuando los datos publicados se asignan al modelo y usted necesita escribir un código para hacer la verificación del modelo usted mismo:
He intentado los tres ejemplos proporcionados en las páginas web vinculadas, pero parece que no funciona para mí.
Algún código:
Mi modelo de vista
...
[Required(ErrorMessageResourceName = "ErrorFirstName", ErrorMessageResourceType = typeof(Mui))]
[MaxLength(50)]
[Display(Name = "Firstname", ResourceType = typeof(Mui))]
public string FirstName { get; set; }
...
El controlador
...
[HttpPost]
public ActionResult Index(POSViewModel model)
{
Contract contract = contractService.GetContract(model.ContractGuid.Value);
if (!contract.IsDirectDebit.ToSafe())
{
ModelState.Remove("BankName");
ModelState.Remove("BankAddress");
ModelState.Remove("BankZip");
ModelState.Remove("BankCity");
ModelState.Remove("AccountNr");
}
if (ModelState.IsValid)
{
...
contractValidationService.Create(contractValidation);
unitOfWork.SaveChanges();
return RedirectToAction("index","thanks");
}
else
{
return Index(model.ContractGuid.ToString());
}
}
Mi prueba de unidad
posViewModel.FirstName = null;
posViewModel.LastName = "";
...
var modelBinder = new ModelBindingContext()
{
ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => posViewModel, posViewModel.GetType()),
ValueProvider = new NameValueCollectionValueProvider(new System.Collections.Specialized.NameValueCollection(), CultureInfo.InvariantCulture)
};
var binder = new DefaultModelBinder().BindModel(new ControllerContext(), modelBinder);
posController.ModelState.Clear();
posController.ModelState.Merge(modelBinder.ModelState);
ActionResult result = posController.Index(posViewModel);
//Assert
mockContractValidationService.Verify(m => m.Create(It.IsAny<ContractValidation>()), Times.Never);
Assert.IsInstanceOfType(result, typeof(ViewResult));
En la vista, estoy usando la validación discreta de JavaScript, y funciona.
Estás tratando de probar dos cosas diferentes al mismo tiempo. El controlador no es responsable de validar el estado del modelo, solo de comportarse de manera diferente según el resultado de esa validación. Por lo tanto, las pruebas unitarias para el controlador no deberían intentar probar la validación, eso debería hacerse en una prueba diferente. En mi opinión deberías tener tres pruebas unitarias:
- Una que verifique si la validación del modelo es correcta.
- Uno que valida si el controlador se comporta correctamente cuando modelstate es válido
- Uno que valida si el controlador se comporta correctamente cuando modelstate no es válido
Así es como puedes hacer eso:
1.Model de validación
[Test]
public void test_validation()
{
var sut = new POSViewModel();
// Set some properties here
var context = new ValidationContext(sut, null, null);
var results = new List<ValidationResult>();
var isModelStateValid =Validator.TryValidateObject(sut, context, results, true);
// Assert here
}
2.Controller con modelstate inválido
[Test]
public void test_controller_with_model_error()
{
var controller = new PosController();
controller.ModelState.AddModelError("test", "test");
ActionResult result = posController.Index(new PosViewModel());
// Assert that the controller executed the right actions when the model is invalid
}
3.Controller con modelstate válido
[Test]
public void test_controller_with_valid_model()
{
var controller = new PosController();
controller.ModelState.Clear();
ActionResult result = posController.Index(new PosViewModel());
// Assert that the controller executed the right actions when the model is valid
}