Frage

Ich bin ziemlich neu für Tests und spöttisch und ich versuche, einen Test zu schreiben, dass meine Validierungslogik Model Fehler sicherzustellen, richtig einstellt.

Was ich sehe ist, dass die controller.ControllerContext.HttpContext.Request gesetzt wird, um das erste Mal, dass ich es überprüfen, aber jedes Mal, nachdem die Anfrage ist null.

Dies verursacht eine Nullreferenz Ausnahme in der PopulateDictionary Methode der * ValueProviderDictionary * Klasse in der MVC-Quelle, weil das Request-Objekt mehrere Male in diesem Verfahren zugegriffen wird, um die Anforderung, ohne sicherzustellen, ist nicht null.

Ich bin miteinander verklebt werden verschiedene Techniken und Helfer, die ich gefunden habe, während die Erforschung, wie einige der Probleme zu überwinden ich in so weit laufen haben, so ich an dieser Stelle ein wenig unsicher bin, wo ich das Problem eingeführt haben.

Bin ich Mock-Objekte falsch hier mit?

Failing Test

//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);
    }
}

Working Test mit 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);
    }
War es hilfreich?

Lösung

Ich würde Ihnen vorschlagen, die ausgezeichnete MVCContrib TestHelper für Einheit testen Sie Ihre ASP.NET MVC-Controller mit Rhino Mocks. Sie werden eine drastische Vereinfachung Ihrer Unit-Tests sehen und erhöht die Lesbarkeit.

Andere Tipps

Was ich aus Ihrer Frage verstehen ist, dass der Controller spöttisch auch durch ein Stub-Objekt ersetzt werden kann, weil das Ziel Controller Verhalten ist nicht zu testen. Auch ich bin nicht wirklich sicher, warum Sie eine FooControllerAccessor benötigen, während Ihre einzige Sorge ist das Model zu behauptet, so ließ ich es aus hier:

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);
}

Um diesen Code verwenden Sie Xania.AspNet.Simulator (zum Zeitpunkt des Schreibens v1.4.0-beta5) installieren sollten arbeitet für Mvc4 und Mvc5

  

PM > install-Paket Xania.AspNet.Simulator -Pre

Weitere Beispiele überprüfen Sie folgendermaßen vor:

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top