Mientras la variable de Bus
es una instancia IBus
, sólo tiene que proporcionar una burlado IBus
aplicación a la clase que contiene este método, y verificar que Enviar fue llamado en él (con el delegado apropiada, si así lo desea) después de invocar el método para la prueba. Más allá de eso, estás probando el Bus.Send
, lo cual no es algo que debas hacer.
public class ClassThatSendsMessages
{
private readonly IBus _bus;
public ClassThatSendsMessages(IBus bus /*, ... */)
{
_bus = bus;
/* ... */
}
public void CodeThatSendsMessage()
{
/* ... */
_bus.Send<IMyMessage>(mm => mm.Property1 = "123");
/* ... */
}
}
public class ClassThatTestsClassThatSendsMessages
{
public void CallCodeThatSendsMessage()
{
//Mock IBus object here
var objectToTest = new ClassThatSendsMessages(mockedIBus /*, ... */)
objectToTest.CodeThatSendsMessage();
//Verify that IBus mock's Send() method was called
}
}
Hay dos formas de acercarse a prueba la lógica del delegado: se puede tratar de derribar el árbol de expresión proporcionado, o se puede cambiar a un método llamado y pasar esa manera. Nunca he metido profundamente en expresiones, así que voy a dar un ejemplo de este último:
public static class MyMessageBuilder
{
public static void Build(IMyMessage message) { /* ... */ }
}
public class ClassThatTestsMyMessageBuilder
{
public void CallCodeThatBuildsMessage()
{
var message = Test.CreateInstance<IMyMessage>(MyMessageBuilder.Build);
//Verify message contents
}
}
Uso:
public class ClassThatSendsMessages
{
private readonly IBus _bus;
public static Action<IMyMessage> BuildMessage { private get; set; }
public ClassThatSendsMessages(IBus bus /*, ... */)
{
_bus = bus;
/* ... */
}
public void CodeThatSendsMessage()
{
/* ... */
_bus.Send<IMyMessage>(mm => BuildMessage (mm));
/* ... */
}
}
No estoy al tanto de un contenedor que puede hacer la inyección delegado constructores, pero tampoco me he esforzado mucho, así que esa podría ser una forma aún mejor de configurar al delegado.
EDITAR
Como recientemente me he encontrado con este problema en mis propias pruebas, y no me gusta tener que tirar el método fuera en su propio constructor. Así que me propuse descubrir si podía probar al delegado "en su lugar". Resulta que se puede:
public class ClassThatTestsClassThatSendsMessages
{
public void CallCodeThatSendsMessage()
{
Action<IMyMessage> messageAction = null;
//Mock IBus object here
mockedIBus.Setup(b => b.Send(Args.IsAny<Action<IMyMessage>>()))
.Callback((Action<IMyMessage> a) => messageAction = a);
var myMessage = Test.CreateInstance<IMyMessage>();
var objectToTest = new ClassThatSendsMessages(mockedIBus /*, ... */)
//Run the code that sends the message
objectToTest.CodeThatSendsMessage();
//Run the code that populates the message
messageAction(myMessage);
//Verify expectations on Setups
//Verify the message contents;
}
}
hay ventajas y desventajas aquí - tirando el constructor mensaje en una interfaz sin duda es más compatible con la SRP de dejarlo como un delegado en línea (como la prueba demuestra claramente: hay que Actúa dos veces para probar todo el código). Sin embargo, presenta beneficios tanto en tamaño de código como en legibilidad.
Además, este código es Moq-specific; No sé si es posible recuperar al delegado de un simulacro de RhinoMocks, o cuál sería la sintaxis para eso.
¿Estás preguntando sobre probar 'Bus.Send', o código que envía mensajes? – arootbeer
arootbeer, estoy preguntando sobre el código de prueba que envía mensajes. El código exacto que deseo probar aparece en la pregunta anterior. – mgamer
Agregué una edición sobre probar el código de delegado en el lugar, en caso de que esté interesado. – arootbeer