c# - Fluent-ASsertions ShouldRaisePropertyChangeFor 不适用于异步任务?

标签 c# multithreading thread-safety async-await fluent-assertions

我有一个实现 INotifyPropertyChanged 的​​简单类,我在另一个线程上调用属性更改,并且我很难让 FluentAsserts 看到 propertyChanged 被调用。如果我在异步任务方法中使用Task.Delay,似乎不会发生这种情况。但如果我只是让线程休眠,它就会发生。

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: Object is not being monitored for events or has already been garbage collected. Use the MonitorEvents() extension method to start monitoring events.

我不明白 MonitorEvents 会关心我是否使用 wait 或 Thread.Sleep。我缺少什么?我知道 await 离开该方法并返回,而 Thread.Sleep 则不会。

因此,当它在等待期间离开 TestMethod1 时,它会触发 FluentAsserts 用于跟踪属性的对象的处置?可以吗?应该是?

最佳答案

是的,事情就像你说的:await暂停当前方法的执行,并创建一个状态机以在Delay完成后返回到该方法。但调用者(UnitTest 引擎)并不期望您的测试是异步的,而只是结束执行,从而导致对象的处置。

Stephen Cleary 写了一篇精彩的文章 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 之后的逻辑可能会在一次性元素被处置后执行。

关于c# - Fluent-ASsertions ShouldRaisePropertyChangeFor 不适用于异步任务?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40896183/

相关文章:

c# - 具有多个来源的 Sitecore 下拉列表

c - 并行更新包含 1000000 个项目的数组

C pthread_join() 产生段错误

java - 在java中使用main和junit得到不同的结果

asp.net - ASP.NET HttpModules 中的线程安全缓存

C++:是否使用 IIFE 线程安全初始化静态局部变量?

Java Executors 和每线程(不是每工作单元)对象?

c# - 如何解析Json获取值

c# - Convert.ToBase64String(byte[]) 和 HttpServerUtility.UrlTokenEncode(byte[]) 有什么区别?

c# - Marshal.PtrToStructure 在 64 位上崩溃