2

У меня есть простой класс, который реализует INotifyPropertyChanged, я вызываю изменение свойства в другом потоке, и мне было довольно сложно получить FluentAsserts, чтобы увидеть, что был вызван propertyChanged. Кажется, это не происходит, если я использую метод Task.Delay в методе async Task. Но это так, если я просто сплю нитку.Fluent-ASsertions ShouldRaisePropertyChangeFor не работает для async Tasks?

SimpleNotify класса:

namespace FluentAssertPropertyThreads 
{ 
    class SimpleNotify : System.ComponentModel.INotifyPropertyChanged 
    { 
     public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; 
     private void onChange(string name) 
     { 
      this.PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(name)); 
     } 

     private int count = 0; 
     public int Count 
     { 
      get 
      { 
       return this.count; 
      } 

      set 
      { 
       if (this.count != value) 
       { 
        this.count = value; 
        this.onChange(nameof(this.Count)); 
       } 
      } 
     } 
    } 
} 

и вот мои модульные тесты:

using FluentAssertions; 
using Microsoft.VisualStudio.TestTools.UnitTesting; 
using System; 
using System.Threading; 
using System.Threading.Tasks; 

namespace FluentAssertPropertyThreads 
{ 
    [TestClass] 
    public class UnitTest1 
    { 
     private SimpleNotify simpleNotify; 
     private int notifyCount; 
     private void bumpCount() 
     { 
      this.simpleNotify.Count++; 
     } 

     private void SimpleNotify_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) 
     { 
      SimpleNotify simpleNotify = sender as SimpleNotify; 
      if (simpleNotify == null) 
      { 
       throw new ArgumentNullException(nameof(sender), "sender should be " + nameof(SimpleNotify)); 
      } 

      if (e.PropertyName.Equals(nameof(SimpleNotify.Count), StringComparison.InvariantCultureIgnoreCase)) 
      { 
       this.notifyCount++; 
      } 
     } 

     [TestInitialize] 
     public void TestSetup() 
     { 
      this.notifyCount = 0; 
      this.simpleNotify = new SimpleNotify(); 
      this.simpleNotify.PropertyChanged += SimpleNotify_PropertyChanged; 
      this.simpleNotify.MonitorEvents(); 

      Thread thread = new Thread(this.bumpCount) 
      { 
       IsBackground = true, 
       Name = @"My Background Thread", 
       Priority = ThreadPriority.Normal 
      }; 
      thread.Start(); 
     } 

     [TestMethod] 
     public async Task TestMethod1() 
     { 
      await Task.Delay(100); 
      this.notifyCount.Should().Be(1);  //this passes, so I know that my notification has be executed. 
      this.simpleNotify.ShouldRaisePropertyChangeFor(x => x.Count);  //but this fails, saying that I need to be monitoring the events (which I am above) 
     } 

     [TestMethod] 
     public void TestMethod2() 
     { 
      Thread.Sleep(100); 
      this.notifyCount.Should().Be(1);  //this passes, so I know that my notification has be executed. 
      this.simpleNotify.ShouldRaisePropertyChangeFor(x => x.Count);  //this passes as I expected 
     } 
    } 
} 

Точная ошибкой является:

System.InvalidOperationException: Объект не проводится мониторинг события или уже был собран мусор. Используйте метод расширения MonitorEvents() для запуска мониторинга событий.

Я не вижу, как MonitorEvents позаботится, если я воспользуюсь ожиданием или Thread.Sleep. Что мне не хватает? Я получаю, что await оставляет метод и возвращается, а Thread.Sleep - нет.

Итак, когда он покидает TestMethod1 во время ожидания, он ударяет по объекту, который FluentAsserts использует для отслеживания свойств? Не могли бы? Должно ли это?

ответ

2

Да, все так, как вы сказали: await приостанавливает выполнение текущего метода и создает конечный автомат, чтобы вернуться к методу после завершения Delay. Но вызывающий (движок UnitTest) не ожидает, что ваши тесты будут асинхронными и просто закончит выполнение, что приведет к удалению объектов.

Стивен Клири написал блестящую MSDN article about Unit testing and async/await keywords, вы, вероятно, следует переместить код к методу возврата Task и ждать все это в тесте, что-то вроде этого:

async Task Testing() 
{ 
    await Task.Delay(100); 
    this.notifyCount.Should().Be(1); 
    this.simpleNotify.ShouldRaisePropertyChangeFor(x => x.Count); 
} 

[TestMethod] 
public async Task TestMethod1() 
{ 
    await Testing(); 
} 

, но это все еще может потерпеть неудачу в логика после await может выполняться после размещения одноразового использования.

0

Похоже, что версия 5.0.0 будет включать поддержку тестов Async с мониторингом.

Этот номер Issue был поднят, и work completed только что ожидал от документации updated и версии 5.0.0.

Но в настоящее время есть пререлиз с кодом изменения 5.0.0-beta2 может получить его из пререлизов на NuGet

Из журнала изменений:

{ломать} Заменен старой резьбовой небезопасный API-интерфейс MonitorEvents с новым модулем расширения монитора , который возвращает потокобезопасный мониторинг , который предоставляет методы, такие как Should().Поднимите() и метаданные, такие как OccurredEvents и MonitoredEvents

Поэтому код с обновленным NuGet будет выглядеть следующим образом:

[TestInitialize] 
public void TestSetup() 
{ 
    this.notifyCount = 0; 
    this.simpleNotify = new SimpleNotify(); 
    this.simpleNotify.PropertyChanged += SimpleNotify_PropertyChanged; 

    Thread thread = new Thread(this.bumpCount) 
    { 
     IsBackground = true, 
     Name = @"My Background Thread", 
     Priority = ThreadPriority.Normal 
    }; 
    thread.Start(); 
} 

[TestMethod] 
public async Task TestMethod1() 
{ 
    using (var MonitoredSimpleNotify = this.simpleNotify.Monitor()) 
    { 
     await Task.Delay(100); 
     this.notifyCount.Should().Be(1); 
     MonitoredSimpleNotify.Should().RaisePropertyChangeFor(x => x.Count); // New API for Monitoring 
    } 
}