asp.net mvc, Как к тестовым контроллерам правильно

Я испытываю затруднения при тестировании контроллеров. Исходный мой контроллер для тестирования выглядел примерно так:

SomethingController CreateSomethingController()
{
    var somethingData = FakeSomethingData.CreateFakeData();
    var fakeRepository = FakeRepository.Create();

    var controller = new SomethingController(fakeRepository);

    return controller;
}

Это хорошо работает для большинства тестирования, пока я не добрался Request.IsAjaxRequest() часть кода. Таким образом я должен был копировать HttpContext и HttpRequestBase. Так мой код, затем измененный для сходства с:

public class FakeHttpContext : HttpContextBase
{
    bool _isAjaxRequest;

    public FakeHttpContext( bool isAjaxRequest = false )
    {
        _isAjaxRequest = isAjaxRequest;
    }

    public override HttpRequestBase Request
    {
        get
        {
            string ajaxRequestHeader = "";

            if ( _isAjaxRequest )
                ajaxRequestHeader = "XMLHttpRequest";

            var request = new Mock<HttpRequestBase>();
            request.SetupGet( x => x.Headers ).Returns( new WebHeaderCollection 
            {
                {"X-Requested-With", ajaxRequestHeader} 
            } );

            request.SetupGet( x => x["X-Requested-With"] ).Returns( ajaxRequestHeader );

            return request.Object;
        }
    }

    private IPrincipal _user;

    public override IPrincipal User
    {
        get
        {
            if ( _user == null )
            {
                _user = new FakePrincipal();
            }
            return _user;
        }
        set
        {
            _user = value;
        }
    }
}


SomethingController CreateSomethingController()
{
    var somethingData = FakeSomethingData.CreateFakeData();
    var fakeRepository = FakeRepository.Create();

    var controller = new SomethingController(fakeRepository);

    ControllerContext controllerContext = new ControllerContext( new FakeHttpContext( isAjaxRequest ), new RouteData(), controller );
     controller.ControllerContext = controllerContext;

    return controller;
}

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

Я, кажется, провожу больше времени, гугля о том, как к фальшивке/фиктивным объектам и затем отлаживая для проверки мои фальшивки корректны, чем фактическая запись тестового кода. Существует ли более легкий путь в протестировать контроллер? Я посмотрел на TestControllerBuilder от MvcContrib, который помогает с некоторыми проблемами, но, кажется, не делает все. Действительно ли там что-либо еще доступно, который сделает задание и позволит мне сконцентрироваться на записи тестов вместо того, чтобы писать насмешки?

Спасибо

5
задан lancscoder 18 June 2010 в 10:25
поделиться

4 ответа

Вы можете использовать некоторые библиотеки, которые предоставляют вам некоторые из этих объектов «из коробки». Например RhinoMock , NMock ... и т.д. Я лично использую Moq - он достаточно хороший и бесплатный. Что мне больше всего нравится в Moq, так это выражения linq.

1
ответ дан 15 December 2019 в 00:50
поделиться

Самый насмешливый движок сделает все это за вас. Я использую RhinoMocks , но есть гораздо больше. Также Moles - очень новый и интересный движок-имитатор (обычно он идет с Pex, который является еще одним боеприпасом в вашем арсенале модульного тестирования)

1
ответ дан 15 December 2019 в 00:50
поделиться

MvcContrib + RhinoMocks. Проверьте TestControllerBuilder в библиотеке MvcContrib.TestHelper. Вот официальная статья: http://mvccontrib.codeplex.com/wikipage?title=TestHelper#Examples.

Вот пример издевательства над контроллером для тестирования UrlHelper: ASP.NET MVC: Mock controller.Url.Action

Вот краткое объяснение того, как использовать TestControllerBuilder: http://codebetter.com/blogs/kyle.baley/archive/2008/03/19/testcontrollerbuilder-in-mvccontrib.aspx

1
ответ дан 15 December 2019 в 00:50
поделиться

Вместо мокинга, вы можете передать IAjaxRequest в конструктор. Или сделать его свойством базового класса конструктора (и использовать инъекцию свойств). Или вы можете сделать ваш конструктор реализующим IAjaxRequest, а затем применить глобальный фильтр действий к базовому классу конструктора, который будет настраивать IAjaxRequest.

Это поможет абстрагировать многие вещи, включая HttpContext. Только не надо абстрагировать IHttpContext, абстрагируйте IUserContext, ISessionStorage, IAuthentication, IRequestDetails...

Другой способ - использовать связывание моделей непосредственно в методах, где вам нужна специфическая информация. Смотрите этот пост для примера. Вы можете сделать биндер, который даст вам IsAjaxRequest, затем вы просто делаете экшен, принимающий этот параметр. Это работает очень хорошо, потому что информация предоставляется именно тому методу, которому она нужна, а не всему контроллеру.

1
ответ дан 15 December 2019 в 00:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: