visual vista una tutorial studio proyecto programar paso pasar net mvc español datos crear controlador asp asp.net-mvc unit-testing tdd moq

asp.net mvc - vista - ¿Cómo se burla de la colección de objetos de sesión utilizando Moq



pasar datos de una vista a un controlador c# (6)

Estoy usando la clase MvcMockHelper de shanselmann para simular algunas cosas de HttpContext usando Moq, pero el problema que estoy teniendo es poder asignar algo a mi objeto de sesión simulado en mi controlador MVC y luego poder leer el mismo valor en la prueba de mi unidad para la verificación propósitos.

Mi pregunta es cómo asignar una colección de almacenamiento al objeto de sesión simulado para permitir que código como session ["UserName"] = "foo" retenga el valor "foo" y que esté disponible en la prueba unitaria.


¡Gracias, @RonnBlack por tu solución! En mi caso, seguí obteniendo esta excepción porque Session.SessionID era nulo:

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

Para resolver este problema, implemento el código de @ RonnBlack de esta manera usando Moq Mock<HttpSessionStateBase> lugar de su 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); }

Para más detalles, consulte http://weblogs.asp.net/gunnarpeipman/using-moq-to-mock-asp-net-mvc-httpcontextbase



Creo que puedes establecer una expectativa sobre el simulacro con un valor específico, debería devolver lo que sea. Los simulacros no se usan como falsificaciones reales, sino como cosas sobre las que se puede afirmar el comportamiento.

Parece que en realidad está buscando un adaptador que pueda envolver alrededor de la sesión para que pueda suministrar una implementación diferente durante las pruebas y durante el tiempo de ejecución, ¿devolvería elementos de la sesión HttpContext?

¿Esto tiene sentido?


El uso de Moq 3.0.308.2 aquí es un ejemplo de la configuración de mi controlador de cuenta en mi prueba de unidad:

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

luego, dentro de su método de controlador, lo siguiente debería devolver "Hello World"

string test = Session["test"].ToString ();


Empecé con MVCMockHelper de Scott Hanselman, agregué una clase pequeña y realicé las modificaciones que se muestran a continuación para permitir que el controlador use Session normalmente y la prueba unitaria para verificar los valores que estableció el controlador.

/// <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"]);

No es perfecto pero funciona lo suficiente para probarlo.


He hecho un simulacro un poco más elaborado que la respuesta publicada por @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); } }