Конфигурация служебной шины MassTransit и модульные тесты

Для MassTransit при настройке новой служебной шины необходимо объявить конечную точку / тип; однако я пытаюсь удалить эту зависимость, чтобы при тестировании на потребителе я мог использовать конечную точку loopback, но в процессе производства она использовала бы фактическую конечную точку 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();
    }
}

person BenM    schedule 03.09.2015    source источник


Ответы (2)


Используйте Внедрение конструктора:

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.

person Mark Seemann    schedule 08.09.2015

Чтобы включить тестирование с использованием 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, если возникнет необходимость.

person 3dd    schedule 08.09.2015