Question

Je suis assez nouveau pour tester et me moquer et j'essaie d'écrire un test qui garantira que ma logique de validation définit correctement les erreurs ModelState.

Ce que je constate, c'est que controller.ControllerContext.HttpContext.Request est défini la première fois que je le vérifie, mais chaque fois après que la requête est nulle.

Ceci provoque une exception de référence null dans la méthode PopulateDictionary de la classe * ValueProviderDictionary * dans le source MVC car l'objet de requête est accédé plusieurs fois dans cette méthode sans garantir que la demande n'est pas null.

Je suis en train de recoller plusieurs techniques et aides que j’ai découverts lors de mes recherches sur la façon de surmonter certains des problèmes que j’ai rencontrés jusqu’à présent. C’est pourquoi je ne suis pas sûr de savoir où j’ai présenté le problème.

Est-ce que j'utilise les objets fictifs de manière incorrecte ici?

Test d'échec

//Test
public void Test_FooController_OnActionExecuting_ShouldMapStateToAFooModel()
{
    //Arrange
    DataAccessFactoryMocks.MockAllDaos();

    var controller = new FooController();

    var testFormCollection = new NameValueCollection();
    testFormCollection.Add("foo.CustomerID", "3");
    testFormCollection.Add("_fooForm", SerializationUtils.Serialize(new FooModel()));

    var mockHttpContext = new MockHttpContext(controller, "POST", testFormCollection, null);

    //Accessor used to run the protected OnActionExecuting method in my controller
    var accessor = new FooControllerAccessor(controller);

    //Request is set, assertion passes
    Assert.IsNotNull(controller.ControllerContext.HttpContext.Request.Form);

    //Request is null when accessing the property a second time, assertion fails
    Assert.IsNotNull(controller.ControllerContext.HttpContext.Request.QueryString);

    //Act
    accessor.OnActionExecuting(new ActionExecutingContext(controller.ControllerContext, MockRepository.GenerateStub<ActionDescriptor>(), new Dictionary<string, object>()));

    //Assert
    Assert.That(controller.ModelState.IsValid == false);
}

Test Helper

//Test helper to create httpcontext and set controller context accordingly
public class MockHttpContext
{
    public HttpContextBase HttpContext { get; private set; }
    public HttpRequestBase Request { get; private set; }
    public HttpResponseBase Response { get; private set; }
    public RouteData RouteData { get; private set; }

    public MockHttpContext(Controller onController)
    {
        //Setup the common context components and their relationships
        HttpContext = MockRepository.GenerateMock<HttpContextBase>();
        Request = MockRepository.GenerateMock<HttpRequestBase>();
        Response = MockRepository.GenerateMock<HttpResponseBase>();

        //Setup the context, request, response relationship
        HttpContext.Stub(c => c.Request).Return(Request);
        HttpContext.Stub(c => c.Response).Return(Response);

        Request.Stub(r => r.Cookies).Return(new HttpCookieCollection());
        Response.Stub(r => r.Cookies).Return(new HttpCookieCollection());

        Request.Stub(r => r.QueryString).Return(new NameValueCollection());
        Request.Stub(r => r.Form).Return(new NameValueCollection());

        //Apply the context to the suppplied controller
        var rc = new RequestContext(HttpContext, new RouteData());
        onController.ControllerContext = new ControllerContext(rc, onController);
    }

    public MockHttpContext(Controller onController, string httpRequestType, NameValueCollection form, NameValueCollection querystring)
    {
    //Setup the common context components and their relationships
    HttpContext = MockRepository.GenerateMock<HttpContextBase>();
    Request = MockRepository.GenerateMock<HttpRequestBase>();
    Response = MockRepository.GenerateMock<HttpResponseBase>();

    //Setup request type based on parameter value
    Request.Stub(r => r.RequestType).Return(httpRequestType);

    //Setup the context, request, response relationship
    HttpContext.Stub(c => c.Request).Return(Request);
    HttpContext.Stub(c => c.Response).Return(Response);

    Request.Stub(r => r.Cookies).Return(new HttpCookieCollection());
    Response.Stub(r => r.Cookies).Return(new HttpCookieCollection());

    Request.Stub(r => r.QueryString).Return(querystring);
    Request.Stub(r => r.Form).Return(form);

    //Apply the context to the suppplied controller
    var rc = new RequestContext(HttpContext, new RouteData());
    onController.ControllerContext = new ControllerContext(rc, onController);
    }
}

Test de fonctionnement avec MvcContrib.TestHelper

    public void Test_FooController_OnActionExecuting_ShouldMapStateToAFooModel()
    {
        //Arrange
        DataAccessFactoryMocks.MockAllDaos();

        TestControllerBuilder builder = new TestControllerBuilder();

        builder.Form.Add("fooModel.CustomerID", "3");

        builder.HttpContext.Request.Stub(r => r.RequestType).Return("POST");

        FooController controller = builder.CreateController<FooController>();

        var accessor = new FooControllerAccessor(controller);

        //Act
        accessor.OnActionExecuting(new ActionExecutingContext(controller.ControllerContext, MockRepository.GenerateStub<ActionDescriptor>(), new Dictionary<string, object>()));

        //Assert
        Assert.IsFalse(controller.ModelState.IsValid);
    }
Était-ce utile?

La solution

Je vous suggère d'utiliser l'excellent MVCContrib TestHelper pour l'unité. tester vos contrôleurs ASP.NET MVC avec Rhino Mocks. Vous constaterez une simplification drastique de vos tests unitaires et une lisibilité accrue.

Autres conseils

Ce que je comprends de votre question est que le moquage de ControllerContext pourrait également être remplacé par un objet stub car l'objectif n'est pas de tester le comportement de ControllerContext. De plus, je ne suis pas vraiment sûr de la raison pour laquelle vous avez besoin d’un FooControllerAccessor alors que votre seul souci est d’affirmer le ModelState, je l’ai donc laissé ici:

public void Test_FooController_OnActionExecuting_ShouldMapStateToAFooModel()
{
    // Arrange
    var action = new FooController()
        .Action("index")
        .RequestData(new Dictionary<string, object>()
        {
            {"foo.CustomerID", 3},
            {"_fooForm", new FooModel()}
        });

    //Act
    var modelState = action.ValidateRequest();

    //Assert
    Assert.That(modelState.IsValid == false);
}

Pour utiliser ce code, vous devez installer Xania.AspNet.Simulator (au moment de l'écriture de v1.4.0-beta5) fonctionne pour Mvc4 et Mvc5

  

PM > paquet d'installation Xania.AspNet.Simulator -Pre

Pour plus d'exemples, consultez les éléments suivants:

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top