c# - net - unit testing mvc controller
¿Por qué la propiedad que quiero burlar necesita ser virtual? (4)
"Entonces ... ¿qué hice es la única manera?"
No, no es la única manera: es mucho mejor implementar una interfaz y burlarse de eso. Entonces sus métodos reales pueden ser virtuales o no como usted elija.
Estoy haciendo algunas pruebas unitarias y burlando algunas propiedades usando Moq .
Ahora, esta es una prueba de controlador (ASP.NET MVC 3). Mis controladores derivan de un controlador abstracto , llamado AbstractController .
Este controlador tiene una dependencia en el contexto Http (para hacer cosas como tematización, lógica específica de dominio basada en encabezados HTTP HOST, etc.).
Esto se hace a través de una propiedad llamada WebSiteSettings :
public abstract class AbstractController : Controller
{
public WebSiteSettings WebSiteSettings { get; private set; }
// other code
}
Observe el conjunto privado: el controlador lo configura. Entonces, lo cambié para usar una interfaz, y eso es de lo que me he burlado:
public IWebSiteSettings WebSiteSettings { get; private set; }
Luego creé un "FakeWebSiteSettings", que se burla del contexto Http para que pueda leer los encabezados HTTP.
El problema es que cuando ejecuto la prueba, recibo una NotSupportedException:
Configuración no válida en un miembro no virtual (anulable en VB): x => x.WebSiteSettings
Aquí está el código de burla relevante:
var mockWebSiteSettings = new Mock<FakeWebSiteSettings>();
var mockController = new Mock<MyController>(SomeRepository);
mockController.Setup(x => x.WebSiteSettings).Returns(mockWebSiteSettings.Object);
_controller = mockController.Object;
var httpContextBase = MvcMockHelpers.FakeHttpContext();
httpContextBase.Setup(x => x.Request.ServerVariables).Returns(new NameValueCollection
{
{"HTTP_HOST","localhost.www.mydomain.com"},
});
_controller.SetFakeControllerContext(httpContextBase.Object);
Si hago que la propiedad WebsiteSettings
virtual , la prueba pasa.
Pero no puedo entender por qué tengo que hacer esto. En realidad, no estoy anulando la propiedad, simplemente me estoy burlando de cómo está configurada.
¿Me estoy perdiendo algo, o estoy haciendo algo mal?
Aunque, todo lo dicho anteriormente es cierto, vale la pena saber que el enfoque de burla de proxy (como el que utiliza moq) no es el único posible.
Visite http://www.typemock.com/ para obtener una solución integral que le permita simular las clases selladas, los métodos no virtuales, etc. Bastante poderosa.
Creé una interfaz y una clase contenedora. p.ej
public interface IWebClient
{
string DownloadString(string url);
}
public class WebClient : IWebClient
{
private readonly System.Net.WebClient _webClient = new System.Net.WebClient();
public string DownloadString(string url)
{
return _webClient.DownloadString(url);
}
}
y luego en las pruebas de tu unidad solo burla la interfaz:
var mockWebClient = new Mock<IWebClient>();
Obviamente, es posible que deba incluir más propiedades / métodos. Pero el truco es
Otro truco útil para otros problemas de burla, como la modificación de la hora actual (siempre uso la fecha y hora UTC):
public interface IDateTimeUtcNowProvider
{
DateTime UtcNow { get; }
}
public class DateTimeUtcNowProvider : IDateTimeUtcNowProvider
{
public DateTime UtcNow { get { return DateTime.UtcNow; } }
}
por ejemplo, si tiene un servicio que se ejecuta cada x minutos, puede simular el IdateTimeProvider y devolver un tiempo que luego se verifica para comprobar si el servicio se ejecutó de nuevo ... o lo que sea.
Moq y otros marcos burlones similares solo pueden simular interfaces, métodos / propiedades abstractas (en clases abstractas) o métodos / propiedades virtuales en clases concretas.
Esto se debe a que genera un proxy que implementará la interfaz o creará una clase derivada que anule esos métodos anulables para interceptar llamadas.