我有一个实现library(formattable)
formattable(table,
list(groupA = color_tile("white", "orange"))
)
的简单类,我在另一个线程上调用属性更改,我很难让Dim currentChar = CInt(Mid(InputBox.Text, i, 1))
If currentChar <> 0 And currentChar <> 1 Then
MessageBox.Show("Value Not Binary", "ERROR", MessageBoxButtons.OK)
InputBox.Text = ""
GoTo skipbin
End If
看到INotifyPropertyChanged
被调用。如果我在FluentAsserts
方法中使用propertyChanged
,似乎不会发生这种情况。但是如果我只是睡觉那就行了。
Task.Delay
类:
async Task
这是我的单元测试:
SimpleNotify
确切的错误是:
System.InvalidOperationException:未监视对象的事件或已对垃圾进行垃圾回收。使用MonitorEvents()扩展方法开始监视事件。
如果我使用等待或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
}
}
}
如何关心。我错过了什么?我得到MonitorEvents
离开方法并返回,而Thread.Sleep
则没有。
因此,当它在等待期间离开await
时,它正在对Thread.Sleep
用于跟踪属性的对象进行处置?可以吗?应该是?
答案 0 :(得分:2)
是的,事情就像你说的那样: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
之后的逻辑可能会在丢弃一次性后执行。
答案 1 :(得分:2)
看起来5.0.0版将包含对带监控的异步测试的支持。
此Issue已被提出,而work completed只是等待文档updated和5.0.0版即将发布。
但目前有一个预发行代码,代码更改5.0.0-beta2可以从NuGet上的预发布版本中获取
从更改日志中
{Breaking}用新的替换旧的线程不安全的MonitorEvents API 监视将返回线程安全监视的扩展方法 暴露像Should()。Raise()和元数据等方法的范围 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
}
}