2008-08-28 6 views
62

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

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

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

+0

Я планировал это сделать. Но нужен только макет для подключения к базе данных. Вместо проверки сопоставления базы данных я переместил функцию в обычный класс и проверил только эту функцию без подключения к базе данных. – MrFox 2013-08-15 07:43:13

ответ

58

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

+16

Это недействительно в MVC3. Передача в пустой RouteData будет генерировать исключения, если в RouteData вызывается не виртуальный, немоксируемый метод GetRequiredString. – ScottKoon 2011-11-03 20:58:00

+2

@ScottKoon Просьба предоставить демонстрацию того, как она должна выглядеть. – Jon 2013-04-30 09:12:40

+1

Ответ на этот вопрос показывает вам, как издеваться над RouteData. http://stackoverflow.com/questions/986183/mocking-the-routedata-class-in-system-web-routing-for-mvc-applications – ScottKoon 2013-12-04 17:19:07

1

Я нахожу, что долгая насмешливая процедура - слишком много трения.

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

Вот example

17

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

Примечание: 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 
... 
2

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

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

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

7

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

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

Процедура для этого, похоже, слегка изменилась в MVC2 (я использую RC1). Решение Phil Haack не работает для меня, если для действия требуется конкретный метод ([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); 
19

Вот единица выборки класс тест с использованием 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); 
    } 
} 
Смежные вопросы