Мокинг контекста контроллера Asp.net-mvc

Таким образом, контекст контроллера зависит от некоторых внутренних компонентов asp.net. Как можно создать чистые макеты для модульных тестов? Похоже, очень легко засорить тесты тоннами настройки, когда мне нужен только, например, Request.HttpMethod для возврата «GET».

Я видел несколько примеров / помощников в сети, но некоторые из них устарели. Подумал, что это хорошее место для хранения последних и лучших вещей.

Я использую последнюю версию моков Rhino

Я собирался сделать это. Но нужен был только макет для подключения к базе данных. Вместо тестирования сопоставления базы данных я переместил функцию в обычный класс и протестировал только эту функцию без подключения к базе данных.

MrFox 15.08.2013 11:43
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
69
1
45 269
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Ответ принят как подходящий

При использовании MoQ это выглядит примерно так:

var request = new Mock<HttpRequestBase>();
request.Expect(r => r.HttpMethod).Returns("GET");
var mockHttpContext = new Mock<HttpContextBase>();
mockHttpContext.Expect(c => c.Request).Returns(request.Object);
var controllerContext = new ControllerContext(mockHttpContext.Object
, new RouteData(), new Mock<ControllerBase>().Object);

Я думаю, что синтаксис Rhino Mocks похож.

Это больше не действует в MVC3. Передача пустого RouteData вызовет исключения, когда невиртуальный, немодируемый метод GetRequiredString вызывается для RouteData.

ScottKoon 04.11.2011 00:58

@ScottKoon Пожалуйста, предоставьте демонстрацию того, как это должно выглядеть

Jon 30.04.2013 13:12

Ответ на этот вопрос показывает, как имитировать RouteData. stackoverflow.com/questions/986183/…

ScottKoon 04.12.2013 21:19

Я считаю, что эта долгая насмешка слишком трогательна.

Лучший способ, который мы нашли - использование ASP.NET MVC в реальном проекте - это абстрагировать HttpContext до интерфейса IWebContext, который просто проходит. Тогда вы можете без труда издеваться над IWebContext.

Вот пример

Вы можете объяснить это поподробнее?

user40097 30.11.2008 03:28

Вот отрывок из ссылки Джейсона. То же, что и метод Фила, но использует носорога.

Примечание: mockHttpContext.Request заглушен, чтобы вернуть mockRequest. перед. Внутренние компоненты mockRequest заглушены. Я считаю, что этот приказ необходим.

// create a fake web context
var mockHttpContext = MockRepository.GenerateMock<HttpContextBase>();
var mockRequest = MockRepository.GenerateMock<HttpRequestBase>();
mockHttpContext.Stub(x => x.Request).Return(mockRequest);

// tell the mock to return "GET" when HttpMethod is called
mockRequest.Stub(x => x.HttpMethod).Return("GET");            

var controller = new AccountController();

// assign the fake context
var context = new ControllerContext(mockHttpContext, 
                  new RouteData(), 
                  controller);
controller.ControllerContext = context;

// act
...

я закончил с этой спецификацией

public abstract class Specification <C> where C: Controller
{
    protected C controller;

    HttpContextBase mockHttpContext;
    HttpRequestBase mockRequest;

    protected Exception ExceptionThrown { get; private set; }

    [SetUp]
    public void Setup()
    {
        mockHttpContext = MockRepository.GenerateMock<HttpContextBase>();
        mockRequest = MockRepository.GenerateMock<HttpRequestBase>();

        mockHttpContext.Stub(x => x.Request).Return(mockRequest);
        mockRequest.Stub(x => x.HttpMethod).Return("GET");


        EstablishContext();
        SetHttpContext();

        try
        {
            When();
        }
        catch (Exception exc)
        {
            ExceptionThrown = exc;
        }
    }

    protected void SetHttpContext()
    {
        var context = new ControllerContext(mockHttpContext, new RouteData(), controller);
        controller.ControllerContext = context;
    }

    protected T Mock<T>() where T: class
    {
        return MockRepository.GenerateMock<T>();
    }

    protected abstract void EstablishContext();
    protected abstract void When();

    [TearDown]
    public virtual void TearDown()
    {
    }
} 

и сок здесь

[TestFixture]
public class When_invoking_ManageUsersControllers_Update :Specification   <ManageUsersController>
{
    private IUserRepository userRepository;
    FormCollection form;

    ActionResult result;
    User retUser;

    protected override void EstablishContext()
    {
        userRepository = Mock<IUserRepository>();
        controller = new ManageUsersController(userRepository);

        retUser = new User();
        userRepository.Expect(x => x.GetById(5)).Return(retUser);
        userRepository.Expect(x => x.Update(retUser));

        form = new FormCollection();
        form["IdUser"] = 5.ToString();
        form["Name"] = 5.ToString();
        form["Surename"] = 5.ToString();
        form["Login"] = 5.ToString();
        form["Password"] = 5.ToString();
    }

    protected override void When()
    {
        result = controller.Edit(5, form);
    }

    [Test]
    public void is_retrieved_before_update_original_user()
    {
        userRepository.AssertWasCalled(x => x.GetById(5));
        userRepository.AssertWasCalled(x => x.Update(retUser));
    }
}

наслаждаться

Или вы можете сделать это с помощью Typemock Isolator без необходимости отправлять поддельный контроллер:

Isolate.WhenCalled(()=>HttpContext.Request.HttpMethod).WillReturn("Get");

В MVC2 процедура для этого, похоже, немного изменилась (я использую RC1). Решение Фила Хаака не работает для меня, если действие требует определенного метода ([HttpPost], [HttpGet]). Если заглянуть в Reflector, похоже, что метод проверки этих атрибутов изменился. MVC теперь проверяет request.Headers, request.Form и request.QueryString на значение X-HTTP-Method-Override.

Если вы добавите макеты для этих свойств, это будет работать:

var request = new Mock<HttpRequestBase>();
request.Setup(r => r.HttpMethod).Returns("POST");
request.Setup(r => r.Headers).Returns(new NameValueCollection());
request.Setup(r => r.Form).Returns(new NameValueCollection());
request.Setup(r => r.QueryString).Returns(new NameValueCollection());

var mockHttpContext = new Mock<HttpContextBase>();
mockHttpContext.Expect(c => c.Request).Returns(request.Object);
var controllerContext = new ControllerContext(mockHttpContext.Object, new RouteData(), new Mock<ControllerBase>().Object);

Это сработало для меня, однако в MVC2 RC мне также пришлось добавить следующее: request.Setup (r => r.Files) .Returns (новый Mock().Объект); в противном случае я получаю исключение nullreferenceexception

Hugo Zapata 10.02.2010 01:10

Вот образец класса модульного теста с использованием MsTest и Moq, который имитирует объекты HttpRequest и HttpResponse. (.NET 4.0, ASP.NET MVC 3.0)

Действие контроллера получает значение из запроса и устанавливает заголовок http в объектах ответа. Аналогичным образом можно смоделировать другие объекты контекста http.

[TestClass]
public class MyControllerTest
{
    protected Mock<HttpContextBase> HttpContextBaseMock;
    protected Mock<HttpRequestBase> HttpRequestMock;
    protected Mock<HttpResponseBase> HttpResponseMock;

    [TestInitialize]
    public void TestInitialize()
    {
        HttpContextBaseMock = new Mock<HttpContextBase>();
        HttpRequestMock = new Mock<HttpRequestBase>();
        HttpResponseMock = new Mock<HttpResponseBase>();
        HttpContextBaseMock.SetupGet(x => x.Request).Returns(HttpRequestMock.Object);
        HttpContextBaseMock.SetupGet(x => x.Response).Returns(HttpResponseMock.Object);
    }

    protected MyController SetupController()
    {
        var routes = new RouteCollection();
        var controller = new MyController();
        controller.ControllerContext = new ControllerContext(HttpContextBaseMock.Object, new RouteData(), controller);
        controller.Url = new UrlHelper(new RequestContext(HttpContextBaseMock.Object, new RouteData()), routes);
        return controller;
    }

    [TestMethod]
    public void IndexTest()
    {
        HttpRequestMock.Setup(x => x["x"]).Returns("1");
        HttpResponseMock.Setup(x => x.AddHeader("name", "value"));

        var controller = SetupController();
        var result = controller.Index();
        Assert.AreEqual("1", result.Content);

        HttpRequestMock.VerifyAll();
        HttpResponseMock.VerifyAll();
    }
}

public class MyController : Controller
{
    public ContentResult Index()
    {
        var x = Request["x"];
        Response.AddHeader("name", "value");
        return Content(x);
    }
}

Огромное спасибо! Это мне очень помогло. Хотел бы я проголосовать за него десять раз.

Maxim Eliseev 22.10.2013 11:57

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