2016-05-06 3 views
1

Я использую Moq, xUnit и Prism 4. Целью моего модульного теста является запуск события и подтверждение того, что свойство изменилось в моей модели просмотра в соответствии с значением из событие. Этот тест, кстати, выходит из строя (Ожидаемый: 5, Actual: 0):Я не понимаю различия в этих модульных тестах

// Version One 
[Fact] 
public void Should_set_DayCount_on_DayCountChangedEvent() 
{ 
    var eaMock = new Mock<IEventAggregator>(); 
    eaMock.SetupCurriculumEvents(); // see below 
    var vm = new CurriculumItemViewModel(eaMock.Object, _systemStatus.Object); 
    vm.Load(_newItem); 
    var dayCount = 5; 

    eaMock.Object.GetEvent<DayCountChangedNotification>().Publish(dayCount); 

    Assert.Equal(dayCount, _vm.DayCount); 
} 

Я устал от создания моей агрегатор события издевается везде, поэтому я создал метод расширения, чтобы сделать грязную работу для меня:

public static void SetupCurriculumEvents(this Mock<IEventAggregator> eaMock) 
{ 
    eaMock.Setup(ea => ea.GetEvent<DayCountChangedNotification>()) 
     .Returns(new DayCountChangedNotification()); 

    // lots of other "notification" events here as well 
} 

Тогда я понял, что я создаю новое событие каждый раз, когда он извлекается из фиктивного агрегатора событий, поэтому Subscribe() на один экземпляр (в VM) не на тот же экземпляр Publish(dayCount) в моем тесте.

Ну, мне кажется, давайте всегда использовать один и тот же объект (путем перезаписи метод обслуживания внутреннего Setup() для этого события), и мы будем хорошо:

// Version Two 
[Fact] 
public void Should_set_DayCount_on_DayCountChangedEvent() 
{ 
    var dayCountChangedEvent = new DayCountChangedNotification(); 
    var eaMock = new Mock<IEventAggregator>(); 
    eaMock.SetupCurriculumEvents(); // still need this for all the other events 
    // overwrite the setup from the extension method 
    eaMock.Setup(ea => ea.GetEvent<DayCountChangedNotification>()) 
     .Returns(dayCountChangedEvent); 

    var vm = new CurriculumItemViewModel(eaMock.Object, _systemStatus.Object); 
    vm.Load(_newItem); 

    var dayCount = 5; 

    dayCountChangedEvent.Publish(dayCount); 

    Assert.Equal(dayCount, _vm.DayCount); 
} 

... который также не зрелищно.

По какой-то причине, я решил попробовать рефакторинга метод расширения, (и вернулся тест блока обратно в первой версии):

public static class MockingExtensions 
{ 
    private static DayCountChangedNotification DayNotification = new DayCountChangedNotification(); 

    public static void SetupCurriculumEvents(this Mock<IEventAggregator> eaMock) 
    { 
     eaMock.Setup(ea => ea.GetEvent<DayCountChangedNotification>()) 
     .Returns(DayNotification); 

     // etc... 
    } 
} 

... который, на мой взгляд, это в основном то же самое - Я всегда возвращаю тот же экземпляр события.

Кикер: Этот тест проходит.

Это здорово и все, но я не понимаю почему он проходит - и если я не понимаю, почему он проходит, то я действительно не знаю, правильно это или нет.

Принято ответ должен объяснить две вещи:

  1. Почему переработан метод расширения с помощью статического экземпляра пройти?
  2. Почему нет версии Two pass?
+0

Объявление статического поля класса не совпадает с локальной переменной. Выполнял ли этот тест только этот тест или выполнял этот тест во время теста с другими тестами? Какова реализация DayCountChangedNotification? –

+0

'DayCountChangedNotification' - это просто пустой класс, который наследуется от класса Prism' CompositePresentationEvent '. Тест проводился как в одиночном режиме, так и в совместном прогоне с другими тестами - результаты были согласованы. –

ответ

0

Я попытался воспроизвести вашу проблему и создал код ниже. Все три теста прошли успешно, поэтому я думаю, что в вопросе чего-то не хватает. Важно знать, что moqObject.Setup (...). Возврат (true) отличается от moqObject.Setup (...). Return (() => true). См. Дополнительную информацию here

namespace Test 
{ 
    using Microsoft.Practices.Prism.Events; 
    using Moq; 
    using System; 
    using Xunit; 

    // Moq 4.2.1510.2205 
    // Prism 4.0.0.0 
    // xunit 2.1.0 

    public class CurriculumItemViewModel 
    { 
     public CurriculumItemViewModel(IEventAggregator agg) 
     { 
      agg.GetEvent<DayCountChangedNotification>().Subscribe((int? x) => { 
       DayCount = x.Value; 
      }); 
     } 

     public int DayCount { get; set; } 
    } 

    public class DayCountChangedNotification : CompositePresentationEvent<int?> 
    { 
     public DateTime Created = DateTime.Now; 
    } 

    public static class Extensions 
    { 
     private static DayCountChangedNotification DayNotification = new DayCountChangedNotification(); 

     public static void SetupCurriculumEventsV1(this Mock<IEventAggregator> eaMock) 
     { 
      eaMock.Setup(ea => ea.GetEvent<DayCountChangedNotification>()) 
        .Returns(new DayCountChangedNotification()); 
     } 

     public static void SetupCurriculumEventsV2(this Mock<IEventAggregator> eaMock) 
     { 
      eaMock.Setup(ea => ea.GetEvent<DayCountChangedNotification>()) 
        .Returns(DayNotification); 
     } 
    } 

    public class TestClass 
    {  
     [Fact] 
     public void ShouldSetDayCountOnDayCountChangedEvent1a() 
     { 
      // Arrange 
      var dayCount = 5; 
      var eaMock = new Mock<IEventAggregator>(); 
      eaMock.SetupCurriculumEventsV1(); 

      var vm = new CurriculumItemViewModel(eaMock.Object); 
      var notification = eaMock.Object.GetEvent<DayCountChangedNotification>(); 
      var notification2 = eaMock.Object.GetEvent<DayCountChangedNotification>(); 

      // Act 
      notification.Publish(dayCount); 

      // Assert 
      Assert.Equal(dayCount, vm.DayCount); 
     } 

     [Fact] 
     public void ShouldSetDayCountOnDayCountChangedEvent2() 
     { 
      // Arrange 
      var dayCount = 5; 
      var eaMock = new Mock<IEventAggregator>(); 
      eaMock.SetupCurriculumEventsV1(); 

      // This will override the setup done by SetupCurriculumEventsV1 
      var notification = new DayCountChangedNotification();   
      eaMock.Setup(ea => ea.GetEvent<DayCountChangedNotification>()) 
        .Returns(notification); 

      var vm = new CurriculumItemViewModel(eaMock.Object); 

      // Act 
      notification.Publish(dayCount); 

      // Assert 
      Assert.Equal(dayCount, vm.DayCount); 
     } 

     [Fact] 
     public void ShouldSetDayCountOnDayCountChangedEvent1b() 
     { 
      // Arrange 
      var dayCount = 5; 
      var eaMock = new Mock<IEventAggregator>(); 

      eaMock.SetupCurriculumEventsV2(); 

      var vm = new CurriculumItemViewModel(eaMock.Object); 
      var notification = eaMock.Object.GetEvent<DayCountChangedNotification>(); 

      // Act 
      notification.Publish(dayCount); 

      // Assert 
      Assert.Equal(dayCount, vm.DayCount);    
     } 
    } 
} 
+0

Отличный ответ - дай мне несколько дней, чтобы просунуть его, и я дам вам знать. –

Смежные вопросы