2017-02-20 1 views
0

Ich versuche Unit-Test eine Methode, und es verwendet ein Wörterbuch zu einer verspotteten Methode, um Anhänge zu einer E-Mail hinzuzufügen. Der Test schlägt immer fehl, der Schritt durch alles scheint korrekt zu sein, aber die Assert scheint das nicht zu bestätigen.Gleichheitsprüfung für Dictionary <string, Stream> mit xunit

Gibt es eine spezielle Art der Unit-Tests Wörterbücher im Allgemeinen, und würde das mit arbeiten für Setup ist für <string, Stream>. Code ist unten, aber denke nicht, dass es irgendetwas damit zu tun hat, aber vielleicht etwas falsch eingerichtet hat, ich denke, ich vermisse etwas Offensichtliches.

[Fact] 
    public void Process_ShouldAttachCsvStreamWhenBuildingEmailMessage() 
    { 
     //Arrange 
     var fixture = new Fixture(); 
     var settings = fixture.Create<Settings>(); 
     var sutFixtures = new SUTFixtures(true); 
     var response = RemoteClientResponseHelper.GetMockHttpWebResponse(sutFixtures.Items); 

     //deal with attachement 
     var csv = sutFixtures.ToCsv(); 
     var bytes = Encoding.GetEncoding("iso-8859-1").GetBytes(csv); 
     var messageAttachments = new Dictionary<string, Stream> {{"MissingImages.csv", new MemoryStream(bytes)}}; 

     var moqClientService = new Mock<IClientService>(); 
     moqClientService.Setup(x => x.Call(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), null)) 
      .Returns(response.Object); 

     Dictionary<string, Stream> attachmentsVerify = null; 

     var moqEmailService = new Mock<IEmailService>(); 
     moqEmailService.Setup(
      x => 
       x.BuildMessage(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), 
        It.IsAny<bool>(), It.IsAny<Dictionary<string, Stream>>())) 
      .Callback<string, string, string, string, bool, Dictionary<string, Stream>>(
       (to, from, subject, body, isHtml, attachments) => 
       { 
        attachmentsVerify = attachments; 
       }); 

     //Act 
     var sut = new MissingImageNotificationStep(moqClientService.Object, moqEmailService.Object, settings); 
     sut.Process(new MappingData() { Parts = sutFixtures.DataTable }); 

     //Assert 
     moqEmailService.Verify(m => m.BuildMessage(It.IsAny<string>(), 
      It.IsAny<string>(), 
      It.IsAny<string>(), 
      It.IsAny<string>(), 
      It.IsAny<bool>(), 
      It.IsAny<Dictionary<string, Stream>>()), Times.Once()); 

     Assert.Equal(messageAttachments, attachmentsVerify); 
    } 

UPDATE

muss sehr faul gewesen sein, wie ich über eine benutzerdefinierte comparer dachte aber dachte, vielleicht war es schon etwas. Ich habe etwas funktioniert, für meinen Fall sowieso, mit Blick auf den Vergleich muss ich ein explizites Casting machen, was in meinem Fall in Ordnung ist, aber ein bisschen stinkt und deshalb benötigt mein Code einen Refactor, auch nicht sicher, ob GetHash irgendetwas in diesem Szenario tut Wenn dieser Code jemals außerhalb der Tests verwendet wird, werde ich das betrachten.

Individuelle Comparer

public class DictionaryComparer : IEqualityComparer<Dictionary<string, Stream>> 
{ 
    private readonly IEqualityComparer<Stream> _valueComparer; 
    public DictionaryComparer(IEqualityComparer<Stream> valueComparer = null) 
    { 
     this._valueComparer = valueComparer ?? EqualityComparer<Stream>.Default; 
    } 

    public bool Equals(Dictionary<string, Stream> x, Dictionary<string, Stream> y) 
    { 
     if (x.Count != y.Count) 
      return false; 

     if (x.Keys.Except(y.Keys).Any()) 
      return false; 

     if (y.Keys.Except(x.Keys).Any()) 
      return false; 

     foreach (var pair in x) 
     { 
      var xValue = pair.Value as MemoryStream; 
      var yValue = y[pair.Key] as MemoryStream; 

      if (xValue.Length != yValue.Length) 
       return false; 

      xValue.Position = 0; 
      yValue.Position = 0; 

      var xArray = xValue.ToArray(); 
      var yArray = yValue.ToArray(); 

      return xArray.SequenceEqual(yArray); 
     } 

     return true; 
    } 

    public int GetHashCode(Dictionary<string, Stream> obj) 
    { 
     unchecked 
     { 
      var hash = 17; 

      foreach (var key in obj.Keys) 
      { 
       hash = hash * 23 + key.GetHashCode(); 
      } 

      return hash; 
     } 
    } 
} 

über XUnit Called

Assert.Equal(messageAttachments, attachmentsVerify, new DictionaryComparer()); 
+1

Haben Sie darüber nachgedacht, die Methode Equal auf Dictionary zu überschreiben? –

Antwort

2

Das aktuelle Verhalten wird erwartet. Da die Nachrichtenanlage und die Anhangsverifizierung sich auf ein anderes Objekt beziehen, wird Assert.Equal als false zurückgegeben.

Sie können Dictionary-Klasse erweitern und Equals und GetHashCode überschreiben. Danach gibt Assert.AreEqual true zurück, wenn es in Ihrem Benutzerwörterbuch verwendet wird.

Sie können auch xunit CollectionAsserts verwenden, um Elemente verschiedener Sammlungen zu vergleichen (in diesem Fall Wörterbuch).

Wenn Sie Gleichheitsgeruch vermeiden möchten, können Sie einen eigenen Gleichheitsvergleich erstellen, der nur öffentliche Eigenschaften überprüft (mithilfe von Reflektion). Testing deep equality

0

Wie ich im Kommentar erwähnt, müssen Sie möglicherweise Equals Methode überschreiben. Standardmäßig basiert der Vergleich auf zwei Referenzobjekten. Ihre Wörterbücher sind unterschiedliche Objekte, obwohl sie denselben Inhalt haben. Sie müssen helfen Assert entscheiden durch Überschreiben gleich Equals und tun tief Vergleich (Inhaltsvergleich).

Wie für CollectionAssert, erfordert es die gleiche Reihenfolge für mein Wissen. Verwenden Sie also entweder OrderBy, bevor Sie Assert anwenden, oder überschreiben Sie Equals. Durch Überschreiben Equals können Sie Wörterbücher überall in Ihrem Code vergleichen.

Hier ist ein Beispiel, wie diese Methode überschrieben werden kann (Sie können das gleiche für Dictionary tun).

public class MetricComparator : IEqualityComparer<Metric> 
{ 
    /// <summary> 
    /// Returns true if two given Metric objects should be considered equal 
    /// </summary> 
    public bool Equals(Metric x, Metric y) 
    { 
     return 
      x.Source == y.Source && 
      x.Type == y.Type && 
      x.Title == y.Title && 
      x.Public == y.Public && 

      x.DayAvg == y.DayAvg && 
      x.DayMax == y.DayMax && 
      x.DayMin == y.DayMin && 

      x.HourAvg == y.HourAvg && 
      x.HourMax == y.HourMax && 
      x.HourMin == y.HourMin && 
      x.CurrentValue == y.CurrentValue; 
    } 
    /// <summary> 
    /// Returns a hash of the given Metric object 
    /// </summary> 
    public int GetHashCode(Metric metric) 
    { 
     return 
      2 * metric.Source.GetHashCode() + 
      3 * metric.Type.GetHashCode() + 
      5 * metric.Title.GetHashCode() + 
      7 * metric.Public.GetHashCode() + 

      11 * metric.DayAvg.GetHashCode() + 
      13 * metric.DayMax.GetHashCode() + 
      17 * metric.DayMin.GetHashCode() + 
      23 * metric.HourAvg.GetHashCode() + 
      29 * metric.HourMax.GetHashCode() + 
      31 * metric.HourMin.GetHashCode() + 
      37 * metric.CurrentValue.GetHashCode(); 
    } 
} 
Verwandte Themen