MassTransit 服务总线配置和单元测试

MassTransit Service Bus Configuration and Unit Tests

对于 MassTransit,在设置新服务总线时必须声明 endpoint/type;但是,我正在尝试删除该依赖项,以便在对消费者进行测试时,我可以利用环回端点,但一旦投入生产,它将使用实际的 msmq 端点。

下面是新服务总线的示例设置:

public class ConsumerService
{
    IServiceBus _bus;

    public void Start()
    {
        // Initalize Service Bus
        _bus = ServiceBusFactory.New(x =>
        {
            //x.UseMsmq();
            x.ReceiveFrom("loopback://localhost/MyQueue");
            x.SetConcurrentConsumerLimit(1);
        });
        _bus.SubscribeConsumer(() => new MyConsumer());
    }

    public void Stop()
    {
        _bus.Dispose();
    }
}

使用构造函数注入:

public class ConsumerService
{
    private readonly IBusInitializer initializer;

    public ConsumerService(IBusInitializer initializer)
    {
        this.initializer = initializer;
    }

    IServiceBus _bus;

    public void Start()
    {
        // Initalize Service Bus
        _bus = ServiceBusFactory.New(x =>
        {
            this.initializer.initialize(x);
            x.SetConcurrentConsumerLimit(1);
        });
        _bus.SubscribeConsumer(() => new MyConsumer());
    }

    public void Stop()
    {
        _bus.Dispose();
    }
}

其中 IInitializer 是正确定义的接口,实现可以是:

public class LoopbackInitializer : IBusInitializer
{
    public void Initialize(WhateverXIs x)
    {
        x.ReceiveFrom("loopback://localhost/MyQueue");
    }
}

public class MsmqInitializer : IBusInitializer
{
    public void Initialize(WhateverXIs x)
    {
        x.UseMsmq();
    }
}

在您的测试中注入所需的实现或 Composition Root

为了使用 MassTransit 启用测试,我所做的是将对服务总线的依赖项封装在一个接口中,然后将此依赖项注入到我的 类.

界面为bus

public interface IPublishBus {
    void Publish<T>(T message) where T : class;
}

然后在生产中使用的实现

public class MassTransitBridge : IPublishBus {
    private IServiceBus _ServiceBus;
    private static readonly string __SubscriptionServiceQueue;
    private static readonly string __MassTransitBridgeQueue;

    static MassTransitBridge() {
        __SubscriptionServiceQueue = ConfigurationManager.AppSettings["mtSubscriptionService"];
        __MassTransitBridgeQueue = ConfigurationManager.AppSettings["mtBridgeQueue"];
    }

    public MassTransitBridge() {
        _ServiceBus = ServiceBusFactory.New(sbc => {
            sbc.UseMsmq(mq => {
                mq.UseSubscriptionService(__SubscriptionServiceQueue);
                mq.Configurator.UseControlBus();
                mq.Configurator.SetCreateTransactionalQueues(true);
            });
            sbc.DisablePerformanceCounters();
            sbc.ReceiveFrom(__MassTransitBridgeQueue);
            sbc.UseControlBus();
            sbc.UseJsonSerializer();
        });
    }

    public void Publish<T>(T message) where T : class {
        _ServiceBus.Publish<T>(message);
    }
}

在测试时,我使用以下 Mock 对象注入我的服务

public class PublishBusMock : IPublishBus {
    public static List<Object> Messages { get; private set; }

    public PublishBusMock() {
        Messages = new List<object>();
    }

    public void Publish<T>(T message) where T : class {
        Messages.Add(message);      
    }

    public static void ClearMessages() {
        Messages = new List<object>();
    }
}

Mock 对象允许我测试 object 被测试的消息是否正确。

同样以这种方式注入它允许我在需要时将 MassTransit 换成实现 IPublishBus 的其他东西