我使用shanselmann's MvcMockHelper類來模擬一些使用Moq的HttpContext的東西,但我遇到的問題是能夠將我的模擬會話對象分配給我的MVC控制器,然後能夠在單元測試中讀取相同的值以進行驗證。你如何使用Moq模擬會話對象集合
我的問題是,如何將存儲集合分配給模擬會話對象,以允許諸如session [「UserName」] =「foo」之類的代碼保留「foo」值並使其在單元測試中可用。
我使用shanselmann's MvcMockHelper類來模擬一些使用Moq的HttpContext的東西,但我遇到的問題是能夠將我的模擬會話對象分配給我的MVC控制器,然後能夠在單元測試中讀取相同的值以進行驗證。你如何使用Moq模擬會話對象集合
我的問題是,如何將存儲集合分配給模擬會話對象,以允許諸如session [「UserName」] =「foo」之類的代碼保留「foo」值並使其在單元測試中可用。
我從Scott Hanselman的MVCMockHelper開始,添加了一個小類,並進行了如下所示的修改,以允許控制器正常使用會話,單元測試驗證由控制器設置的值。
/// <summary>
/// A Class to allow simulation of SessionObject
/// </summary>
public class MockHttpSession : HttpSessionStateBase
{
Dictionary<string, object> m_SessionStorage = new Dictionary<string, object>();
public override object this[string name]
{
get { return m_SessionStorage[name]; }
set { m_SessionStorage[name] = value; }
}
}
//In the MVCMockHelpers I modified the FakeHttpContext() method as shown below
public static HttpContextBase FakeHttpContext()
{
var context = new Mock<HttpContextBase>();
var request = new Mock<HttpRequestBase>();
var response = new Mock<HttpResponseBase>();
var session = new MockHttpSession();
var server = new Mock<HttpServerUtilityBase>();
context.Setup(ctx => ctx.Request).Returns(request.Object);
context.Setup(ctx => ctx.Response).Returns(response.Object);
context.Setup(ctx => ctx.Session).Returns(session);
context.Setup(ctx => ctx.Server).Returns(server.Object);
return context.Object;
}
//Now in the unit test i can do
AccountController acct = new AccountController();
acct.SetFakeControllerContext();
acct.SetBusinessObject(mockBO.Object);
RedirectResult results = (RedirectResult)acct.LogOn(userName, password, rememberMe, returnUrl);
Assert.AreEqual(returnUrl, results.Url);
Assert.AreEqual(userName, acct.Session["txtUserName"]);
Assert.IsNotNull(acct.Session["SessionGUID"]);
這不是完美的,但它足以用於測試。
我認爲你可以設置一個具體值的模擬期望它應該返回任何。嘲笑不是作爲實際的假貨,而是你可以斷言的行爲。
這聽起來像你實際上正在尋找一個適配器,你可以環繞會話,你可以在測試期間和運行時提供不同的實現它會返回HttpContext會話項?
這是否有意義?
我剛剛發現了一個很好的例子,說明Oxite團隊如何僞造他們的HttpSessionState並在該假冒中維護一個SessionStateItemCollection集合。這應該和我的情況一樣。
編輯:
URL這個例子是http://oxite.codeplex.com/sourcecontrol/changeset/view/33871?projectName=oxite#388065
使用起訂量3.0.308.2這裏是我的賬戶控制器設置在我的單元測試的例子:
private AccountController GetAccountController()
{
.. setup mocked services..
var accountController = new AccountController (..mocked services..);
var controllerContext = new Mock<ControllerContext>();
controllerContext.SetupGet(p => p.HttpContext.Session["test"]).Returns("Hello World");
controllerContext.SetupGet(p => p.HttpContext.User.Identity.Name).Returns(_testEmail);
controllerContext.SetupGet(p => p.HttpContext.Request.IsAuthenticated).Returns(true);
controllerContext.SetupGet(p => p.HttpContext.Response.Cookies).Returns(new HttpCookieCollection());
controllerContext.Setup (p => p.HttpContext.Request.Form.Get ("ReturnUrl")).Returns ("sample-return-url");
controllerContext.Setup (p => p.HttpContext.Request.Params.Get ("q")).Returns ("sample-search-term");
accountController.ControllerContext = controllerContext.Object;
return accountController;
}
那麼你的控制器內方法如下應返回「Hello World」
string test = Session["test"].ToString();
很好的答案!這正是我所需要的單元測試數據 – Rob 2010-08-23 09:31:04
我做了一個稍微複雜莫克比@RonnBlack
public class HttpSessionStateDictionary : HttpSessionStateBase
{
private readonly NameValueCollection keyCollection = new NameValueCollection();
private readonly Dictionary<string, object> _values = new Dictionary<string, object>();
public override object this[string name]
{
get { return _values.ContainsKey(name) ? _values[name] : null; }
set { _values[name] = value; keyCollection[name] = null;}
}
public override int CodePage
{
get { throw new NotImplementedException(); }
set { throw new NotImplementedException(); }
}
public override HttpSessionStateBase Contents
{
get { throw new NotImplementedException(); }
}
public override HttpCookieMode CookieMode
{
get { throw new NotImplementedException(); }
}
public override int Count
{
get { return _values.Count; }
}
public override NameObjectCollectionBase.KeysCollection Keys
{
get { return keyCollection.Keys; }
}
public Dictionary<string, object> UnderlyingStore
{
get { return _values; }
}
public override void Abandon()
{
_values.Clear();
}
public override void Add(string name, object value)
{
_values.Add(name, value);
}
public override void Clear()
{
_values.Clear();
}
public override void CopyTo(Array array, int index)
{
throw new NotImplementedException();
}
public override bool Equals(object obj)
{
return _values.Equals(obj);
}
public override IEnumerator GetEnumerator()
{
return _values.GetEnumerator();
}
public override int GetHashCode()
{
return (_values != null ? _values.GetHashCode() : 0);
}
public override void Remove(string name)
{
_values.Remove(name);
}
public override void RemoveAll()
{
_values.Clear();
}
public override void RemoveAt(int index)
{
throw new NotImplementedException();
}
public override string ToString()
{
return _values.ToString();
}
public bool Equals(HttpSessionStateDictionary other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Equals(other._values, _values);
}
}
發佈
謝謝你,@RonnBlack您的解決方案的答案!就我而言,我一直得到這個例外,因爲Session.SessionID爲空:
System.NotImplementedException was unhandled by user code
HResult=-2147467263
Message=The method or operation is not implemented.
Source=System.Web
StackTrace:
at System.Web.HttpSessionStateBase.get_SessionID()
爲了解決這個問題,我實現@ RonnBlack的代碼中使用的起訂量Mock<HttpSessionStateBase>
這種方式,代替他的MockHttpSession:
private readonly MyController controller = new MyController();
[TestFixtureSetUp]
public void Init()
{
var session = new Mock<HttpSessionStateBase>();
session.Setup(s => s.SessionID).Returns(Guid.NewGuid().ToString());
var request = new Mock<HttpRequestBase>();
var response = new Mock<HttpResponseBase>();
var server = new Mock<HttpServerUtilityBase>();
// Not working - IsAjaxRequest() is static extension method and cannot be mocked
// request.Setup(x => x.IsAjaxRequest()).Returns(true /* or false */);
// use this
request.SetupGet(x => x.Headers).Returns(
new System.Net.WebHeaderCollection
{
{"X-Requested-With", "XMLHttpRequest"}
});
var context = new Mock<HttpContextBase>();
//context
context.Setup(ctx => ctx.Request).Returns(request.Object);
context.Setup(ctx => ctx.Response).Returns(response.Object);
context.Setup(ctx => ctx.Session).Returns(session.Object);
context.Setup(ctx => ctx.Server).Returns(server.Object);
context.SetupGet(x => x.Request).Returns(request.Object);
context.SetupGet(p => p.Request.Url).Returns(new Uri("http://www.mytesturl.com"));
var queryString = new NameValueCollection { { "code", "codeValue" } };
context.SetupGet(r => r.Request.QueryString).Returns(queryString);
controller.ControllerContext = new ControllerContext(context.Object, new RouteData(), controller);
}
有關詳細信息,請參閱http://weblogs.asp.net/gunnarpeipman/using-moq-to-mock-asp-net-mvc-httpcontextbase
,以便其他人通過搜索查找此問題,可否請您發佈一條指向您發現的信息的鏈接以回答問題。 – 2009-03-02 23:08:35
+1鏈接獲取更多信息。 – 2009-05-05 02:50:23
我想他是在談論這個課程: http://oxite.codeplex。com/sourcecontrol/changeset/view/33871?projectName = oxite#388065 – andrecarlucci 2009-07-01 14:30:28