views:

74

answers:

1

Hi,

I would like to test the validation of submitted DTO. This is the bare bone of a controller create action:

[AcceptVerbs(HttpVerbs.Post)]
        public RedirectToRouteResult Create(SomeDTO SomeDTO)
        {
            SomeObject SomeObject = null;

            try
            {
SomeObject = this.RepositoryService.getSomeObjectRepository().Create(SomeDTO, this.RepositoryService);
            }
            catch (BrokenRulesException ex)
            {
                ex.AddModelStateErrors(ModelState, "Model");
            }
            catch (Exception e)
            {
                ModelState.AddModelError("Exception", e.Message);
            }

            TempData["ViewData"] = ViewData;
            TempData["SomeDTO "] = SomeDTO;

            return ModelState.IsValid ? RedirectToAction("SomeObjectDetail", new { Id = SomeObject.Id }) : RedirectToAction("Form");
        }

The mechanics , although not relevant, is as follows: I have a strongly typed view = form which submits a dto to this action which either returns the form or the details page of the created object.

I would like to unit test whether the Model contains certain key/errorMessage combinations given some invalid dto. Did someone do similar stuff? Any pointers would be very much appreciated.

Thanks.

Best wishes,

Christian

A: 

In your case, I don't think you really want to test the model state. Rather, you should simply use the test set up to induce a correct/incorrect model state, then test that the appropriate result is returned under the conditions. You can use separate tests to validate the various conditions under which the model is valid/invalid, though, if you use DataAnnotations, I don't see much point in testing that they and the model binding infrastructure work correctly. Presumably Microsoft has already done this.

Original, based on the (faulty) assumption that a ViewResult was being returned

I think it should be something like this.

[TestMethod]
public void TestCreate()
{
     // set up

    var result = Create( invalidDTO ) as ViewResult;

    var modelState = result.ViewData.ModelState;

    Assert.IsFalse( modelState.IsValid );

    var errors = modelState.Errors;

    Assert.AreEqual( 1, errors.Count );
    Assert.AreEqual( errors[0].ErrorMessage, "some error message" );
}
tvanfosson
That looks great thanks. I will try it tomorrow. Thanks.
csetzkorn
@csetzkom - there might be a few syntax issues (I'm on my Mac), but that's the basic idea.
tvanfosson
yeah thanks but i get the idea - i think - will find out soon and then accept your answer
csetzkorn
First problem my create action 'returns' RedirectToRouteResult - is it actually possible to get hold of the modelstate somehow?
csetzkorn
@csetzkom -- Sorry I missed that. I assumed you were returning a ViewResult since you wanted to test the model state. I would not valid model state in this instance because it isn't exposed outside the method. Rather you should set up the test(s) so that the model state is/isn't valid (other tests can be made on the DTO class itself to test conditions under which it would be valid/invalid) and then test that the method returns the correct redirect result given the conditions. I'll update.
tvanfosson
Sorry I do not understand the actions (both!) I redirect to return a ViewResult object and the model is stored like this: TempData["ViewData"] = ViewData so at the end of the day this action should return a ViewResult. Does this make sense? On the otherhand, could you please suggest a way to achieve the same behaviour whilst returning a ViewResult object 'directly'? Thanks!
csetzkorn
@csetzkom - in the event of an invalid model, though, you don't really care about the temp data. Normally, you'd simply return the view result corresponding to the create action and let it render the validation errors. Only on success (valid model) would you redirect to the detail view. At that point you might want to validate that you've set the temp data on the controller properly -- which you should be able to do via the controller TempData property. Note that since it uses the session you will probably need to mock the HttpContextBase and HttpSessionStateBase properties.
tvanfosson
I need at least TempData["SomeDTO "] as I would like to maintain the form values despite validation errors. anyway i think I just unit test the repositories for now. thanks for all you help
csetzkorn
@cseztkom - the normal way is to re-render the view when you have errors and provide the same model to it, updating the model with any data that wasn't present in the request parameters, typically only things like data to populate menus and other administrative data. While you might want to cache it when doing the redirect on success, you certainly don't need to when regenerating the view with errors. In that case you shouldn't be redirection, IMO.
tvanfosson