Проблемы с издевательством над запросом MVC ControllerContext

StackOverflow https://stackoverflow.com/questions/1422347

Вопрос

Я довольно новичок в тестировании и макетировании, и я пытаюсь написать тест, который гарантирует, что моя логика проверки правильно устанавливает ошибки ModelState.

Что я вижу, так это то, что контроллер.ControllerContext.HttpContext.Request устанавливается при первой проверке, но каждый раз после этого Запрос равно нулю.

Это вызывает исключение нулевой ссылки в Населенный пункт метод класса *ValueProviderDictionary * в исходном коде MVC, потому что к объекту запроса обращаются несколько раз в этом методе, не гарантируя, что запрос не равен нулю.

Я склеиваю несколько методов и помощников, которые я нашел, исследуя, как преодолеть некоторые из проблем, с которыми я столкнулся до сих пор, поэтому на данный момент я немного не уверен, где я, возможно, ввел проблему.

Я неправильно использую здесь фиктивные объекты?

Неудачный тест

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

Рабочий тест с использованием 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);
    }
Это было полезно?

Решение

Я бы предложил вам использовать превосходный MVCContrib TestHelper для устройства тестирование ваших контроллеров ASP.NET MVC с помощью Rhino Mocks. Вы увидите резкое упрощение модульных тестов и повышение читабельности.

Другие советы

Что я понимаю из вашего вопроса, так это то, что насмешка над ControllerContext также может быть заменена объектом-заглушкой, потому что целью не является тестирование поведения ControllerContext.Кроме того, я не совсем уверен, зачем вам нужен FooControllerAccessor, в то время как ваша единственная забота - подтвердить ModelState, поэтому я оставил это здесь:

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

Чтобы использовать этот код, вы должны установить Xania.AspNet.Simulator (на момент написания версии v1.4.0-beta5) работает для Mvc4 и Mvc5

Премьер -министр > установить-пакет Xania.AspNet.Simulator -Предварительный

Для получения дополнительных примеров ознакомьтесь со следующим:

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top