Контролируемый контекст контроллера Asp.net-mvc - PullRequest
67 голосов
/ 28 августа 2008

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

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

Я использую последнюю версию насмешек для носорога

Ответы [ 7 ]

63 голосов
/ 28 августа 2008

Использование 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 похож.

21 голосов
/ 22 февраля 2013

Вот пример класса модульного тестирования, использующего 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);
    }
}
18 голосов
/ 29 августа 2008

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

Примечание: 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
...
10 голосов
/ 24 декабря 2009

Процедура для этого, кажется, немного изменилась в 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);
7 голосов
/ 29 января 2009

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

Isolate.WhenCalled(()=>HttpContext.Request.HttpMethod).WillReturn("Get");
2 голосов
/ 21 октября 2008

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

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

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

0 голосов
/ 29 августа 2008

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

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

Вот пример

...