unit testing - ¿Cómo te burlas de una clase Sellada?
unit-testing language-agnostic (10)
Burlarse de las clases selladas puede ser bastante doloroso. Actualmente, estoy a favor de un patrón de Adaptador para manejar esto, pero algo sobre simplemente se siente extraño.
Entonces, ¿cuál es la mejor forma de burlarse de las clases selladas?
Las respuestas de Java son más que bienvenidas . De hecho, me gustaría anticipar que la comunidad Java ha estado lidiando con esto por más tiempo y tiene mucho que ofrecer.
Pero aquí están algunas de las opiniones de .NET:
¿Hay alguna manera de implementar una clase sellada desde una interfaz ... y burlarse de la interfaz?
Algo en mí siente que tener clases selladas es malo en primer lugar, pero así soy yo :)
Aunque actualmente solo está disponible en versión beta, creo que vale la pena tener en cuenta la característica de shim del nuevo marco Fakes (parte de la versión Beta de Visual Studio 11 ).
Los tipos de corrección proporcionan un mecanismo para desviar cualquier método .NET a un delegado definido por el usuario. Los tipos de corrección son generados por código por el generador de Fakes, y utilizan delegados, que llamamos tipos de corrección, para especificar las nuevas implementaciones de métodos. Debajo del capó, los tipos de corrección utilizan devoluciones de llamada que se inyectaron en tiempo de ejecución en el método cuerpos MSIL.
Personalmente estaba buscando usar esto para burlarme de los métodos en clases de framework selladas como DrawingContext.
Casi siempre evito tener dependencias en clases externas en lo profundo de mi código. En cambio, prefiero usar un adaptador / puente para hablar con ellos. De esa manera, estoy tratando con mi semántica, y el dolor de traducir está aislado en una clase.
También hace que sea más fácil cambiar mis dependencias a largo plazo.
Creo que Moles , de Microsoft Research, te permite hacer eso. Desde la página de Moles:
Los moles se pueden utilizar para desviar cualquier método .NET, incluidos los métodos no virtuales / estáticos en tipos sellados.
ACTUALIZACIÓN: hay un nuevo marco llamado "Fakes" en el próximo lanzamiento de VS 11 que está diseñado para reemplazar a Moles:
The Fakes Framework en Visual Studio 11 es la próxima generación de Moles & Stubs, y eventualmente lo reemplazará. Sin embargo, las falsificaciones son diferentes a las de Moles, por lo tanto, pasar de Moles a Fakes requerirá algunas modificaciones a su código. Una guía para esta migración estará disponible en una fecha posterior.
Requisitos : Visual Studio 11 Ultimate, .NET 4.5
El problema con TypeMock es que excusa un mal diseño. Ahora, sé que a menudo el mal diseño de otra persona es oculto, pero permitirlo en su proceso de desarrollo puede llevar muy fácilmente a sus propios malos diseños.
Creo que si va a utilizar un marco de burla, debería usar uno tradicional (como Moq) y crear una capa de aislamiento alrededor de lo que no puede ser mofado, y burlarse de la capa de aislamiento en su lugar.
Es perfectamente razonable burlarse de una clase sellada porque muchas clases marco están selladas.
En mi caso, estoy tratando de burlarme de la clase MessageQueue de .NET para que pueda TDD mi elegante lógica de manejo de excepciones.
Si alguien tiene ideas sobre cómo superar el error de Moq con respecto a "Configuración no válida en un miembro no invalidable", házmelo saber.
código:
[TestMethod]
public void Test()
{
Queue<Message> messages = new Queue<Message>();
Action<Message> sendDelegate = msg => messages.Enqueue(msg);
Func<TimeSpan, MessageQueueTransaction, Message> receiveDelegate =
(v1, v2) =>
{
throw new Exception("Test Exception to simulate a failed queue read.");
};
MessageQueue mockQueue = QueueMonitorHelper.MockQueue(sendDelegate, receiveDelegate).Object;
}
public static Mock<MessageQueue> MockQueue
(Action<Message> sendDelegate, Func<TimeSpan, MessageQueueTransaction, Message> receiveDelegate)
{
Mock<MessageQueue> mockQueue = new Mock<MessageQueue>(MockBehavior.Strict);
Expression<Action<MessageQueue>> sendMock = (msmq) => msmq.Send(It.IsAny<Message>()); //message => messages.Enqueue(message);
mockQueue.Setup(sendMock).Callback<Message>(sendDelegate);
Expression<Func<MessageQueue, Message>> receiveMock = (msmq) => msmq.Receive(It.IsAny<TimeSpan>(), It.IsAny<MessageQueueTransaction>());
mockQueue.Setup(receiveMock).Returns<TimeSpan, MessageQueueTransaction>(receiveDelegate);
return mockQueue;
}
Generalmente tomo la ruta de crear una interfaz y una clase de adaptador / proxy para facilitar la burla del tipo sellado. Sin embargo, también experimenté omitiendo la creación de la interfaz y haciendo que el proxy no sea sellado con métodos virtuales. Esto funcionó bien cuando el proxy es realmente una clase base natural que encapsula y los usuarios forman parte de la clase sellada.
Al tratar con el código que requería esta adaptación, me cansé de realizar las mismas acciones para crear la interfaz y el tipo de proxy, así que implementé una biblioteca para automatizar la tarea.
El código es algo más sofisticado que el ejemplo dado en el artículo al que hace referencia, ya que produce un ensamblaje (en lugar del código fuente), permite la generación de código en cualquier tipo y no requiere tanta configuración.
Para obtener más información, consulte esta página .
Me encontré con este problema recientemente y después de leer / buscar en la web, parece que no hay un camino fácil, excepto para utilizar otra herramienta como se mencionó anteriormente. O crudo de manejar las cosas como lo hice yo:
- Crear instancia de clase sellada sin tener que llamar al constructor.
System.Runtime.Serialization.FormatterServices.GetUninitializedObject (instanceType);
Asigna valores a tus propiedades / campos a través de la reflexión
- YourObject.GetType (). GetProperty ("PropertyName"). SetValue (dto, newValue, null);
- YourObject.GetType (). GetField ("FieldName"). SetValue (dto, newValue);
Mi regla general es que los objetos que tengo que burlar también deben tener una interfaz común. Creo que esto es correcto en cuanto al diseño y hace que las pruebas sean mucho más fáciles (y generalmente es lo que obtienes si haces TDD). Se puede leer más acerca de esto en la última publicación de Google Testing Blog (consulte el punto 9).
Además, he estado trabajando principalmente en Java en los últimos 4 años y puedo decir que puedo contar con una mano la cantidad de veces que he creado una clase final (sellada). Otra regla aquí es que siempre debería tener una buena razón para sellar una clase, en lugar de sellarla por defecto.
Para .NET, podría usar algo como TypeMock , que usa la API de creación de perfiles y le permite enganchar llamadas a casi cualquier cosa.