2017-02-20 35 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 делает что-либо в этом сценарии , если этот код когда-либо используется вне тестов, я буду смотреть на это.

Пользовательские 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; 
     } 
    } 
} 

Вызывается с помощью XUnit

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

Вы считали отмену равного метода в словаре? –

ответ

2

Текущее поведение, как ожидается. Поскольку вложение и привязка сообщения относятся к другому объекту, Assert.Equal возвращает false.

Вы можете расширить класс Dictionary и переопределить Equals и GetHashCode. После этого Assert.AreEqual вернет true, когда будет использоваться ваш пользовательский словарь.

Вы также можете использовать xunit CollectionAsserts, чтобы сравнить элементы разных коллекций (словарь в этом случае).

Если вы хотите избежать запаха равенства, вы можете создать свой собственный сравнительный анализатор, который проверяет только общедоступные свойства (используя отражение). Testing deep equality

0

Как я уже упоминал в комментарии, вам может потребоваться переопределить метод Equals. По умолчанию сравнение основано на ссылках на два объекта. Ваши словари - разные объекты, хотя с одним и тем же содержимым. Вам необходимо помочь Assert решить путем переопределения равным Equals и делать глубокий сравнение (содержание сравнение).

Что касается CollectionAssert, для этого требуется тот же заказ. Так что либо вы используете OrderBy перед применением Assert, либо переопределяете 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(); 
    } 
}