2015-05-06 1 views
2

ВопросИспользования NserviceBus.Testing как протестировать опубликованное событие, когда код не запускаются с помощью обработчика сообщений

Если текущий метод испытывается инициируются с помощью какого-либо другого метода, чем входящее сообщение (в handler), как вы проверяете публикацию событий. Проблема с NServiceBus.Testing (насколько я понимаю) заключается в том, что она очень ориентирована на обработчики тестов, которые, в свою очередь, вызывают отправку/публикацию сообщений/событий.

фон:

У нас есть целый ряд унаследованных систем, и в настоящее время усилия, чтобы перейти к правильной реализации SOA, мы должны интегрироваться с некоторыми унаследованными заданий DB. Эти задания выполняют действия в БД каждые 15 минут, которые мы хотим подключить и публиковать события при возникновении определенных условий.

У нас есть служба Windows, которая работает в NsbHost, но не содержит обработчиков. Вместо этого мы используем Quartz для создания внутреннего задания cron, которое выполняется каждую минуту, опроса БД для записей, соответствующих указанному шаблону, и публикует событие перед обновлением БД, чтобы сказать, что мы обработали эту запись. Вот как мы интегрируем старые и новые системы.

Очевидно, что это не идеальная ситуация, но при условии, что мы находимся на этапе перехода в нашей реализации SOA так же хорошо, как и сейчас.

Детали и код:

Наш интерфейс события мы публикуем выглядит как этот

public interface IPremiumAdjustmentFinalised 
    { 
     string PolicyNumber { get; set; } 
     decimal Amount { get; set; } 
     DateTime FinalisedOn { get; set; } 
    } 

Кодекса фактически опубликовать событие является

Bus.Publish<IPremiumAdjustmentFinalised>(e => 
    { 
     e.Amount = AdjustmentAmount; 
     e.PolicyNumber = PolicyNumber; 
     e.FinalisedOn = LastModifiedOn; 
    }); 

Это все работает отлично и мы можем проверить, что вызов был выполнен с использованием MOQ таким образом:

eventPublisher.MethodToTest(); 
    bus.Verify(x => x.Publish(It.IsAny<Action<IPremiumAdjustmentFinalised>>()), Times.Once); 

где шина - это новый макет, вставленный в конструктор.

Но я хочу проверить значения внутри IPremiumAdjustmentFinalised. Я нахожу это очень трудным, я думаю, главным образом потому, что это интерфейс, а не конкретный класс.

Мы попытались использовать NServiceBus.Testing, чтобы попытаться проверить сгенерированное событие, но безрезультатно.

Кто-нибудь знает, как проверить значения в событии в данном сценарии?

ответ

3

Есть 2 решения, которые мы придумали

Решение 1:

Создать конкретный класс, наследующий интерфейс и шины публиковать что вместо

public class PremiumAdjustmentFinalisedEvent : IPremiumAdjustmentFinalised 
{ 
    public string PolicyNumber { get; set; } 
    public decimal Amount { get; set; } 
    public DateTime FinalisedOn { get; set; } 
} 

Этот класс только используемый в отправителе, обработчик на другом конце все равно будет слушать события типа IPremiumAdjustmentFinalised.

Отправка события изменится на этот

var message = new PremiumAdjustmentFinalisedEvent 
{ 
    Amount = AdjustmentAmount, 
    PolicyNumber = PolicyNumber, 
    FinalisedOn = LastModifiedOn 
};  
Bus.Publish<IPremiumAdjustmentFinalised>(message); 

, что позволяет нам проверить таким образом:

bus.Verify(x => x.Publish(It.Is<IPremiumAdjustmentFinalised>(paf => 
    paf.Amount == AdjustmentAmount && 
    paf.FinalisedOn == LastModifiedOn && 
    paf.PolicyNumber == PolicyNumber)), Times.Once); 

Это не идеальное решение, как нам нужно добавить код к живому решению, чтобы дать но он работает хорошо и легко понять.

Решение 2:

Реализовать собственный IBUS и утверждающие объекты являются правильными в том, что:

class myBus : IBus 
{ 
    public void Publish<T>(Action<T> messageConstructor) 
    { 
     IPremiumAdjustmentFinalised paf = new PremiumAdjustmentFinalised(); 
     var ipaf = (T) paf; 
     messageConstructor(ipaf); 

     Assert.AreEqual(paf.Amount, AdjustmentAmount); 
     Assert.AreEqual(paf.FinalisedOn, LastModifiedOn); 
     Assert.AreEqual(paf.PolicyNumber, PolicyNumber); 
    } 
    ... 
    <<Leave the rest of the methods not implemented>> 
    ... 
} 

С моей собственной тестовой реализацией IPremiumAdjustmentFinalised (аналогично решению 1, но в тестовом проекте)

Теперь тест выглядит так

var myBus = new myBus(); 
eventPublisher = new AdjustmentFinaliserEventPublisher(myBus); 
eventPublisher.UpdateAndPublishFinalisedAdjustments(); 

Мне нравится это решение, так как оно не изменяет код в реальном времени только для тестирования, но недостатком является то, что существует большая реализация IBus с множеством не реализованных методов на нем.

0

После копания результатов Google в течение нескольких дней после нахождения этой статьи, по-прежнему не было никаких реальных указаний, кроме этого. После реализации решения 2 я решил найти более легкий способ и придумал следующее, используя Moq в качестве насмешливой библиотеки.

///Declarations 
private Mock<IPremiumAdjustmentFinalised > _mockEvent = new Mock<IPremiumAdjustmentFinalised >(); 
private readonly Mock<IBus> _mockBus = new Mock<IBus>(); 
private SomeEventPublisher _someEventPublisher; 

[SetUp] 
public void Setup() 
{ 
    //Instruct moq to set up implementations for the event interface's properties. 
    _mockEvent.SetupAllProperties(); 

    _mockBus.Setup(b => b.Publish(It.IsAny<Action<IPremiumAdjustmentFinalised>>())) 
    .Callback((Action<IPremiumAdjustmentFinalised> messageConstructor) => 
    { 
     //Execute the constructor provided in the action in the event publisher, so the event data can be interrogated. 
     messageConstructor(_mockEvent.Object); 
    }); 

    _someEventPublisher = new SomeEventPublisher(_mockBus); 
} 


[Test] 
public void SomeEventPublisherTest() 
{ 
    _someEventPublisher.PublishSomeEvent(AdjustmentAmount, LastModifiedOn, PolicyNumber) 

    Assert.AreEqual(_mockEvent.Object.Amount, AdjustmentAmount); 
    Assert.AreEqual(_mockEvent.Object.FinalisedOn, LastModifiedOn); 
    Assert.AreEqual(_mockEvent.Object.PolicyNumber, PolicyNumber); 
}