我不明白这些单元测试中的差异

时间:2016-05-06 19:44:55

标签: unit-testing moq xunit prism-4

我正在使用Moq,xUnit和Prism 4.我的单元测试的目标是触发事件并确认我的视图模型中的属性已更改以匹配事件的值。顺便说一下,这个测试失败了(预期:5,实际: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
}

然后我意识到每次从模拟事件聚合器检索时我都在创建一个新事件,因此一个实例(在VM中)的Subscribe()与{{不在同一个实例上1}}在我的测试中。

嗯,请问,让我们总是使用相同的对象(通过覆盖此事件的扩展方法的Publish(dayCount)),我们会很好:

Setup()

......也失败了。

出于某种原因,我决定尝试重构扩展方法,(并将单元测试还原为版本1):

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

...在我看来,基本上是一回事 - 我总是返回相同的事件实例。

以下是踢球者:此测试通过

这很好,但是我不明白为什么它通过了 - 如果我不明白为什么它会过去,那么我真的不知道它是否正确。

接受的答案需要解释两个的事情:

  1. 为什么带有静态实例的重构扩展方法会通过?
  2. 为什么第二版没有通过?

1 个答案:

答案 0 :(得分:0)

我尝试重现您的问题,并在下面创建了代码。所有三个测试都成功了,所以我认为问题中缺少一些东西。重要的是要知道moqObject.Setup(...)。Return(true)与moqObject.Setup(...)不同.Resurn(()=&gt; 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);            
        }
    }
}