Tant que votre variable Bus
est que vous pouvez simplement exemple IBus
, fournir une implémentation IBus
raillé à la classe qui contient cette méthode, et vérifier que Envoyer a appelé (avec le délégué approprié, si vous le désirez) après que la méthode a été appelée pour le test. Au-delà de cela, vous commencez à tester Bus.Send
lui-même, ce qui n'est pas quelque chose que vous devriez faire.
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
}
}
Il existe deux façons d'aborder tester la logique du délégué: vous pouvez essayer de briser l'arbre d'expression fourni, ou vous pouvez changer à une méthode appelée et le transmettre de cette façon. Je n'ai jamais eu profondément dans les expressions, donc je vais vous donner un exemple de ce dernier:
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
}
}
Utilisation:
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));
/* ... */
}
}
Je ne suis pas au courant d'un récipient qui peut faire l'injection de délégué constructeurs, mais je n'ai pas regardé très dur non plus, ce qui pourrait être une meilleure façon de définir le délégué.
EDIT
Comme je l'ai récemment rencontré ce problème dans mes propres tests, et je ne aime pas vraiment avoir à tirer la méthode sur dans son propre constructeur. Je me suis donc mis à découvrir si je pouvais tester le délégué "en place". Il se avère que vous pouvez:
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;
}
}
Il y a des compromis ici - tirer le constructeur de message dans une interface est certainement plus conforme à la SRP que de le laisser en tant que délégué en ligne (comme le test démontre clairement: vous devez Agir deux fois pour tester tout le code). Cependant, il présente des avantages à la fois en termes de taille de code et de lisibilité.
En outre, ce code est spécifique au Moq; Je ne sais pas s'il est possible de récupérer le délégué d'un simulacre de RhinoMocks, ou quelle serait la syntaxe pour cela.
Demandez-vous de tester 'Bus.Send', ou du code qui envoie des messages? – arootbeer
arootbeer, je pose des questions sur le code de test qui envoie des messages. Le code exact que je veux tester est donné dans la question ci-dessus. – mgamer
J'ai ajouté une modification concernant le test du code de délégué sur place, au cas où vous seriez intéressé. – arootbeer