代码之家  ›  专栏  ›  技术社区  ›  mgamer

测试总线。使用NServiceBus发送应用程序

  •  6
  • mgamer  · 技术社区  · 16 年前

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

    你将如何进行这样一个代码的单元测试?

    2 回复  |  直到 16 年前
        1
  •  3
  •   Matt Mills    16 年前

    只要你的 Bus IBus 例如,您可以简单地提供 IBus公司 Bus.Send 这不是你应该做的。

    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
        }
    }
    

    有两种方法可以测试委托的逻辑:您可以尝试分解提供的表达式树,或者将其更改为命名方法并按此方式传递。我从未深入研究过表达式,因此我将提供后者的一个示例:

    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
        }
    }
    

    用法:

    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));
            /* ... */
        }
    }
    

    我不知道有一个容器可以对构造函数进行委托注入,但是我也没有仔细研究,所以这可能是设置委托的更好方法。

    编辑

    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;
        }
    }
    

    这里有一个折衷方案——将消息生成器拉到接口中肯定比将其保留为内联委托更符合SRP(测试清楚地表明:为了测试所有代码,必须执行两次操作)。但是,它在代码大小和可读性方面都有好处。

    这 代码是Moq特有的;我不知道是否有可能从RhinoMocks mock中获取委托,或者它的语法是什么。

        2
  •  2
  •   Adam Fyles    16 年前

    查看NSB附带的测试框架,它在下面使用Rhino: http://nservicebus.com/UnitTesting.aspx . 下载中有几个示例可以与NUnit一起使用。你也可以让它在MSTest下工作。