views:

213

answers:

1

I'm trying to build a test for my custom model binder, but not having any success. The call to base.BindModel always returns a null. Is there a way to test custom binding when using LINQ to Entities? foo in this case is a table in the db with two fields - a numeric and a text value.

fooBinder.cs:

public override Object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
  var obj = (foo)base.BindModel(controllerContext, bindingContext);
  return obj;
}

I'm trying to do a simple test (there's some extra debris in here, I've tried a number of different approaches):

fooBinderTest.cs:

fooBinder binder;
ControllerContext controllerContext;
ModelBindingContext bindingContext;

[TestInitialize]
public void Initialize()
{
  controllerContext = MockControllerContext().Object;

  FormCollection form = new FormCollection
      {
        {"foo_A","2" },
        {"foo_B", "FooB" }
      };
  var valueProvider = form.ToValueProvider();

  bindingContext = new ModelBindingContext()
  {
    ModelState = new ModelStateDictionary(),
    ModelType = typeof(foo),
    ModelName = "foo",
    ValueProvider = valueProvider
  };

  binder = new fooBinder();

}

public static Mock<ControllerContext> MockControllerContext()
{
  var context = new Mock<ControllerContext>();
  var sessionState = new Mock<HttpSessionStateBase>();
  var response = new Mock<HttpResponseBase>();
  var request = new Mock<HttpRequestBase>();
  var serverUtility = new Mock<HttpServerUtilityBase>();

  var form = new FormCollection
        {
        {"foo_A","2" },
        {"foo_B", "FooB" }
        };

  context.Setup(c => c.HttpContext.Session).Returns(sessionState.Object);
  context.Setup(c => c.HttpContext.Response).Returns(response.Object);
  context.Setup(c => c.HttpContext.Request).Returns(request.Object);
  context.Setup(c => c.HttpContext.Server).Returns(serverUtility.Object);
  context.Setup(c => c.HttpContext.User.Identity.Name).Returns("Test");
  context.Setup(c => c.HttpContext.Request.Form).Returns(form);

  return context;
}


[TestMethod]
public void TestDefault()
{
  foo myFoo = (foo)binder.BindModel(controllerContext, bindingContext);
  Assert.IsNotNull(myFoo);
}
+1  A: 

L2E is a red herring here.

You must specify your custom model binder since you don't have the MVC infrastructure running in the test.

Here's how I do it (MVC 2; 1 is a bit different).

    internal static T Bind<T>(string prefix, FormCollection collection, ModelStateDictionary modelState)
    {
        var mbc = new ModelBindingContext()
        {
            ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, typeof(T)),
            ModelName = prefix,
            ModelState = modelState,
            ValueProvider = collection.ToValueProvider()
        };
        IModelBinder binder = new MyCustomModelModelBinder();
        var cc = new ControllerContext();

        return binder.BindModel(cc, mbc) as T;
    }

    internal static T BindAndAssertValid<T>(string prefix, FormCollection collection)
    {
        var msd = new ModelStateDictionary();
        var result = Bind<T>(prefix, collection, msd);
        if (!msd.IsValid)
        {
            Assert.Fail(ModelStateValidationSummary(msd));
        }
        return result;
    }
Craig Stuntz
Unfortunately, we're on MVC 1.
chris
You can do almost exactly the same thing on MVC 1; only the properties you set when constructing the ModelBindingContext change.
Craig Stuntz
IIRC you set `Model` rather than `ModelMetadata`. But it's been a while.
Craig Stuntz