Mocking Requirements for TryUpdateModel in ASP.Net RC1
Asked Answered
N

1

5

I am in the process of writing some unit tests for my controllers in RC1. Here is the controller's public signature I'm testing:

        [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult AcceptColleague()
    {

The implementation inside the AcceptColleague uses the TryUpdateModel(colleague) method of populating the Colleague object from the form fields. However, I'm running into a "Object reference not set to an instance of an object" error on the TryUpdateModel line while trying to unit test the method.

Here is my unit test code:

            // definition
        HomeController controller = new HomeController();
        IColleagueRepository fakeColleagueRepo = MockRepository.GenerateMock<IColleagueRepository>();
        Colleague requestedColleauge = new Colleague();
        EmployeeInfo currentUser = new EmployeeInfo();            
        HttpContextBase fakeHttpContext = MockRepository.GenerateMock<HttpContextBase>();
        HttpRequestBase fakeHttpRequest = MockRepository.GenerateMock<HttpRequestBase>();
        ControllerContext fakeContext = MockRepository.GenerateMock<ControllerContext>(fakeHttpContext, new RouteData(), controller);
        NameValueCollection fakeForm = new NameValueCollection();

        // expectations
        fakeColleagueRepo.Expect(c => c.Read(1234)).Return(requestedColleauge);
        fakeColleagueRepo.Expect(c => c.Update(requestedColleauge));
        fakeColleagueRepo.Expect(c => c.Add(new Colleague())).IgnoreArguments().Constraints(Is.NotNull());
        fakeContext.Expect(cx => cx.HttpContext).Return(fakeHttpContext);
        fakeHttpContext.Expect(hcx => hcx.Request).Return(fakeHttpRequest);
        fakeHttpRequest.Expect(hr => hr.Form).Return(fakeForm);

        // setup
        controller.ColleagueRepository = fakeColleagueRepo;
        controller.ControllerContext = fakeContext;
        requestedColleauge.TargetEmployeeInfoId = 123456;
        requestedColleauge.GeneratedEmployeeInfoId = 654321;
        currentUser.EmployeeInfoId = 123456;
        fakeForm.Add("ColleagueId", "22222");

        // action
        RedirectToRouteResult result = controller.AcceptColleague() as RedirectToRouteResult;

        // validation
        Assert.IsNotNull(result, "AcceptColleague() did not return RedirectToRouteResult");

Am I missing something on the mocking or should I be using a different public signature like AcceptColleague(Colleague colleague) and then testing the ModelState.IsValid property?

If so, how don't see a way I can mock the read only ModelState property off of the controller?

Niobium answered 9/2, 2009 at 21:43 Comment(0)
C
13

TryUpdateModel and ModelState both require zero mocks in RC 1. The only thing that you have to supply is a ValueProvider. For that, you can use FormCollection.ToValueProvider().

You'll still need to mock your repository, but there is nothing that you need to mock in the framework for this functionality. Try this:

    FormCollection fakeForm = new FormCollection();
    fakeForm.Add("ColleagueId", "22222");
    controller.ValueProvider = fakeForm.ToValueProvider();

    // action

Note: No mocked HttpContext needed, unless your code requires it.

Copperplate answered 9/2, 2009 at 21:53 Comment(3)
Craig, thanks a lot. I guess I missed that in the floating documentation out there. I works like a charm now. Thanks again, ColeNiobium
actually you need to provide a context, if you dont you get ArgumentNullException, Value cannot be null.Parameter name: controllerContextSpathe
Mvc 5.2.3 gave the Null Exception Omar described above. controller.ControllerContext = new ControllerContext(); Allows the unit test to progress for me.Amain

© 2022 - 2024 — McMap. All rights reserved.