2008-08-28 130 views
62

所以控制器上下文依賴於一些asp.net內部。有什麼方法可以乾淨地模擬這些單元測試?似乎很容易堵塞測試與噸設置時,我只需要,例如,Request.HttpMethod返回「GET」。嘲笑Asp.net-mvc控制器上下文

我在網上看過一些例子/幫手,但有些已過時。認爲這將是一個保持最新和最好的好地方。

我使用的是最新版本的犀牛嘲笑

+0

我正在考慮這樣做。但只需要模擬數據庫連接。我沒有測試數據庫映射,而是將函數移到常規類中,只測試該函數,而沒有數據庫連接。 – MrFox 2013-08-15 07:43:13

回答

58

使用最小起訂量,它看起來是這樣的:

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

我覺得犀牛嘲笑語法類似。

+16

這在MVC3中不再有效。當在RouteData上調用非虛擬,非可模擬方法GetRequiredString時,傳入空的RouteData將引發異常。 – 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)。如果該操作需要特定方法([HttpPost],[HttpGet]),Phil Haack的解決方案對我無效。在Reflector中探索,看起來驗證這些屬性的方法已經改變。 MVC現在檢查request.Headers,request.Formrequest.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的起訂量和樣本單元測試類嘲笑的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); 
    } 
}