2017-02-20 34 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(); 
    } 
} 
相关问题