Haciendo Unit Test de MVC

Trabajando en el proyecto de agendas de la comunidad Alt.NET Hispano, había armado algunos test de unidad del sitio web, el cual está construido sobre MVC3.

Los modelos de la presentación utilizan DataAnnotations para hacer las validaciones y en el controller se valida que el modelo sea correcto. Me encontré con el problema de que, al ejecutar los tests, al Controller le llegaba siempre un Model válido, aún cuando el mismo no lo era.

Nelo me explicó el porque de esto: el Controller valida el modelo en base a lo que le llega por el HttpContext, y yo seguramente no estaba armandolo.

Después de verificar que tenía razón, encontré los siguientes links que me dieron la pista de como hacerlo.

En pocas palabras, lo que se hace es pasarle al Controller a testear, un ControllerContext, luego se arma el formulario (el diccionario de clave-valor que viaja por Post) y de ahí, se lo enlaza al modelo. Para esto, armamos (bah!!! Copiamos de uno de los posts) un método que se encarga de esto:

protected static TModel BindModel<TModel>(Controller controller, 
    IValueProvider valueProvider) where TModel : class
{
  var binder = ModelBinders.Binders.GetBinder(typeof(TModel));
  var bindingContext = new ModelBindingContext()
  {
    FallbackToEmptyPrefix = true,
    ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType
         (null, typeof(TModel)),
    ModelName = "NotUsedButNotNull",
    ModelState = controller.ModelState,
    PropertyFilter = (name => true),
    ValueProvider = valueProvider
  };
  return (TModel)binder.BindModel(controller.ControllerContext, 
      bindingContext);
}
y en lugar de armar el model cargando las propiedades del objeto, lo que se hace, es armar el formulario y luego, pasarlo por el método BindModel. Antes, hacíamos esto:
var eventoController = new EventoController();
var eventoNew = new EventoNewModel
{
  Duracion = new TimeSpan(0, 0, 0),
  Fecha = DateTime.Today.AddDays(15),
  Hora = new TimeSpan(18, 0, 0),
  Ponentes = new[] { GetGuidPersona() },
  TipoEvento = (int)TipoEvento.Van,
  Titulo = "Título"
};
y ahora, queda así:
var eventoController = new EventoController
    { ControllerContext = ControllerCtx };
var form = new FormCollection
{
  {"Duracion", (new TimeSpan(0, 0, 0)).ToString()},
  {"Fecha", (DateTime.Today.AddDays(15)).ToString()},
  {"Hora", (new TimeSpan(18, 0, 0)).ToString()},
  {"Ponentes", GetGuidPersona().ToString()},
  {"TipoEvento", ((int)TipoEvento.Van).ToString()},
  {"Titulo", "Título"}
};
var eventoNew = BindModel<EventoNewModel>(eventoController, form); 

Para el proyecto, terminamos armando una clase de la cual, deben heredar los unit test de los Controllers; el MvcControllerTestsBase.cs. Se puede utilizar de esta manera: EventoControllerTests.cs