2010-10-11 5 views
6

tengo este código en mi aplicación .NET aplicación usando NServiceBus:Prueba Bus.Send en una aplicación que utiliza NServiceBus

Bus.Send<IServiceStarted>(e => 
          { 
            e.ServiceInfo = ReadServiceInfo(); 
            e.EventTime = DateProvider.Now; 
          }); 

¿Cómo usted va sobre la unidad de pruebas de un código de este tipo?

+0

¿Estás preguntando sobre probar 'Bus.Send', o código que envía mensajes? – arootbeer

+0

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

+0

Agregué una edición sobre probar el código de delegado en el lugar, en caso de que esté interesado. – arootbeer

Respuesta

3

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.

+1

Si el código que se está probando es un manejador de mensajes, puede usar la biblioteca NServiceBus.Testing que puede simular el bus por usted, y si usa setter injection para la propiedad IBus, también lo inyectará en su manejador. –

+0

arootbeer, la parte más difícil para mí es cómo verificar que se haya llamado al método de envío con el delegado apropiado. Rhino Mocks ofrece un método AssertWasCalled que acepta restricciones en los argumentos, pero hay una restricción que le permite verificar si el método fue llamado con un delegado apropiado. – mgamer

+0

Puede intentar usar GetArgumentsForCallsMadeOn para sacar al delegado e inspeccionar sus propiedades: http://kashfarooq.wordpress.com/2009/01/10/rhino-mocks-and-getargumentsforcallsmadeon/ – PatrickSteele

2

Compruebe el marco de prueba que viene con NSB, está utilizando Rhino debajo: http://nservicebus.com/UnitTesting.aspx. hay varias muestras en la descarga que lo usan con NUnit. También puede hacer que funcione bajo MSTest.

Cuestiones relacionadas