2017-02-20 28 views
0

我試圖單元測試一個方法,並且它使用傳遞給模擬方法的字典向電子郵件添加附件。測試總是失敗,通過一切似乎是正確的,但Assert似乎沒有驗證。用xunit檢查字典<字符串,流>

是否有一種特殊的單元測試字典的方式,一般來說,它的工作原理是設置爲<string, Stream>。代碼在下面,但不要認爲它與任何東西有關,但可能已經錯誤地設置了一些東西,我想我錯過了一些明顯的東西。

[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,我想過一個自定義比較,但也許認爲這是已經存在的東西

一定很懶惰。我有一些工作,無論如何,我的情況下,看着比較器我必須做一些明確的鑄造這是罰款在我的情況,但有點臭,因此我的代碼需要重構,也不知道GetHash在這種情況下做任何事情,如果這個代碼在測試之外使用,我會看看。

自定義比較

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

通過的xUnit

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

您是否考慮重寫Dictionary上的Equal方法? –

回答

2

稱爲當前是正常現象。由於消息附件和attachmentverify引用了不同的對象,因此Assert.Equal返回false。

您可以擴展Dictionary類,並覆蓋Equals和GetHashCode。之後,Assert.AreEqual將在您的自定義字典中使用時返回true。

您還可以使用xunit CollectionAsserts來比較不同集合的項目(本例中的字典)。

如果你想避免平等氣味,你可以創建自己的相等比較器,只檢查公共屬性(使用反射)。 Testing deep equality

0

正如我在評論中提到的,您可能需要重寫Equals方法。 默認情況下,比較基於參考兩個對象。儘管內容相同,但您的字典是不同的對象。你需要幫助Assert決定通過重寫平等Equals和做比較(內容比較)。

至於CollectionAssert,就我所知,它需要相同的順序。 因此,無論您在申請Assert之前使用OrderBy,還是覆蓋Equals。 通過覆蓋Equals,您將能夠比較代碼中任意位置的字典。

下面是如何覆蓋該方法的示例(您可能希望對字典執行相同的操作)。

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(); 
    } 
} 
相關問題