2016-05-06 4 views
1

Ich verwende Moq, XUnit und Prism 4. Mein Unit Test Ziel ist es, ein Ereignis auszulösen und zu bestätigen, dass eine Eigenschaft in meinem View-Modell geändert hat, um den Wert von entsprechen das Ereignis. Dieser Test, der übrigens nicht (Erwartet: 5, Aktuell: 0):Ich verstehe nicht den Unterschied in diesen Unit-Tests

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

Ich habe genug von meinem Event Aggregator mock überall einrichten, so dass ich erstellt eine Erweiterungsmethode, die schmutzige Arbeit zu tun für mich:

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 
} 

Dann erkannte ich, dass ich jedes Mal ein neues Event bin zu schaffen es aus dem Mock Ereignis-Aggregator, so dass die Subscribe() auf eine Instanz (in der VM) ist abgerufen wird nicht auf der gleichen Instanz wie die Publish(dayCount) in meinem Test.

Nun, mir scheint, wollen wir immer nur das gleiche Objekt verwenden (durch die Erweiterung Methode des Setup() für dieses Ereignis überschreiben) und wir werden gut sein:

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

... die auch spektakulär ausfällt.

Aus irgendeinem Grund habe ich beschlossen, Refactoring die Erweiterungsmethode, um zu versuchen, (und kehrte das Gerät Test Version zurück One):

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... 
    } 
} 

..., die mir in den Sinn, im Grunde ist die gleiche Sache - Ich gebe immer dieselbe Instanz des Ereignisses zurück.

Hier ist der Kicker: dieser Test besteht.

Das ist großartig und alles, aber ich verstehe nicht warum es passiert - und wenn ich nicht verstehe, warum es vorbei ist, dann weiß ich nicht wirklich, ob es richtig ist oder nicht.

akzeptierte Antwort braucht zwei Dinge zu erklären:

  1. Warum die Refactoring-Extension-Methode mit der statischen Instanz übergeben?
  2. Warum wird Version zwei nicht bestanden?
+0

Das Deklarieren eines statischen Klassenfelds ist nicht dasselbe wie eine lokale Variable. Haben Sie diesen Test nur ausgeführt oder haben Sie diesen Test während eines Testlaufs mit anderen Tests ausgeführt? Was ist die Implementierung von DayCountChangedNotification? –

+0

'DayCountChangedNotification' ist nur eine leere Klasse, die von Prisms 'CompositePresentationEvent ' -Klasse erbt. Der Test wurde sowohl als Einzellauf als auch als gemeinsamer Lauf mit anderen Tests durchgeführt - die Ergebnisse waren konsistent. –

Antwort

0

Ich habe versucht, Ihr Problem zu reproduzieren und den folgenden Code erstellt. Alle drei Tests waren erfolgreich, daher denke ich, dass in der Frage etwas fehlt. Es ist wichtig zu wissen, dass moqObject.Setup (...) .Ret (true) nicht dasselbe ist wie moqObject.Setup (...). Return (() => true). Weitere Informationen 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

Große Antwort - geben Sie mir ein paar Tage, um durch sie zu stochern, und ich werde Sie wissen lassen. –

Verwandte Themen