所以控制器上下文依賴於一些asp.net內部。有什麼方法可以乾淨地模擬這些單元測試?似乎很容易堵塞測試與噸設置時,我只需要,例如,Request.HttpMethod返回「GET」。嘲笑Asp.net-mvc控制器上下文
我在網上看過一些例子/幫手,但有些已過時。認爲這將是一個保持最新和最好的好地方。
我使用的是最新版本的犀牛嘲笑
所以控制器上下文依賴於一些asp.net內部。有什麼方法可以乾淨地模擬這些單元測試?似乎很容易堵塞測試與噸設置時,我只需要,例如,Request.HttpMethod返回「GET」。嘲笑Asp.net-mvc控制器上下文
我在網上看過一些例子/幫手,但有些已過時。認爲這將是一個保持最新和最好的好地方。
我使用的是最新版本的犀牛嘲笑
使用最小起訂量,它看起來是這樣的:
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);
我覺得犀牛嘲笑語法類似。
這在MVC3中不再有效。當在RouteData上調用非虛擬,非可模擬方法GetRequiredString時,傳入空的RouteData將引發異常。 – ScottKoon 2011-11-03 20:58:00
@ScottKoon請提供一個它應該看起來像什麼樣子的演示 – Jon 2013-04-30 09:12:40
這個問題的答案告訴你如何模擬RouteData。 http://stackoverflow.com/questions/986183/mocking-the-routedata-class-in-system-web-routing-for-mvc-applications – ScottKoon 2013-12-04 17:19:07
我發現長時間的嘲弄程序太過摩擦。
我們發現的最佳方式 - 在真實項目中使用ASP.NET MVC - 將HttpContext抽象爲簡單通過的IWebContext接口。那麼你可以毫不費力地嘲笑IWebContext。
這裏是一個example
下面是從賈森的鏈接片段。它和菲爾的方法一樣,但使用犀牛。
注意: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隔離,無需做發送虛假控制器:
Isolate.WhenCalled(()=>HttpContext.Request.HttpMethod).WillReturn("Get");
這個過程似乎在MVC2中略有變化(我使用RC1)。如果該操作需要特定方法([HttpPost]
,[HttpGet]
),Phil Haack的解決方案對我無效。在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);
下面是使用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);
}
}
我正在考慮這樣做。但只需要模擬數據庫連接。我沒有測試數據庫映射,而是將函數移到常規類中,只測試該函數,而沒有數據庫連接。 – MrFox 2013-08-15 07:43:13