如何为 ObservableCollections 的线程亲和性编写失败测试

发布于 2024-12-29 05:59:01 字数 494 浏览 1 评论 0原文

我有一个线程安全的可观察集合替换,我想为其编写单元测试。为了避免误报,我尝试编写一个多线程测试来证明对象无法添加到 ObservableCollection<> 中。不会失败,这样我就可以将它与我的交换并看着它变绿。我只是无法让这个测试失败(使用 NUnit)。

到目前为止,我尝试过的没有特定顺序:

  • 在不同线程上创建集合并在当前线程上更新
  • 在当前线程上创建集合并在备用线程上更新
  • 使用不同的线程机制
    • 线程启动
    • 调度员
    • 后台工作人员
  • 使用不同的单元状态
    • 测试本身和/或一个或两个线程上的 STA 和 MTA 的所有组合
  • 创建一个 WPF 窗口来保存集合并手动操作 Dispatcher 帧以模拟运行时环境。

自定义集合本身在实际代码中运行良好,因此现在这更像是一项学术练习;我的线程信心已经动摇了:)

I have a thread safe observable collection replacement which I would like to write a unit test for. To avoid a false positive I'm trying to write a multi-threaded test that proves an object cannot be added to an ObservableCollection<> without failing so I can swap it with mine and watch it go green. I just cannot get this test to fail (using NUnit).

In no particular order I've so far tried:

  • Creating the collection on a different thread and updating on current
  • Creating the collection on the current thread and updating on an alternate
  • Using different threading mechanisms
    • ThreadStart
    • Dispatcher
    • BackgroundWorker
  • Using different apartment states
    • All combinations of STA and MTA on the test itself and/or one or both of the threads
  • Creating a WPF Window to hold the collection and manipulating the Dispatcher frames manually to simulate a runtime environment.

The custom collection itself is working fine in real code so this is now more of an academic exercise than anything; My threading confidence has been shaken :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

还给你自由 2025-01-05 05:59:01

您正在尝试测试不存在的东西...

此测试没有理由失败,因为 ObservableCollection 类本身不具有线程亲和性。它不是线程安全的,但这只是意味着如果您在没有适当锁定的多线程场景中使用它,则行为将是不可预测的;如果您这样做,ObservableCollection 中没有任何内容会显式抛出异常。

但是, CollectionView 类确实可以 具有线程关联性,这就是为什么您无法从不同的线程将项目添加到 ObservableCollection(如果存在) CollectionView 附加到它(例如,当您将 ItemsControl 绑定到集合时,就会发生这种情况)。但抛出异常的是 CollectionView,而不是 ObservableCollection...

采用以下代码:

var list = new ObservableCollection<string>();
// var view = CollectionViewSource.GetDefaultView(list);
ThreadPool.QueueUserWorkItem(_ => list.Add("foo"));

它执行时不会抛出异常,但如果取消注释该行创建 CollectionView 时,它会抛出 NotSupportedException

该类型的CollectionView不支持对其进行更改
来自与 Dispatcher 线程不同的线程的 SourceCollection。

You're trying to test something that is not there...

There is no reason for this test to fail, because the ObservableCollection<T> class itself doesn't have thread affinity. It's not thread-safe, but it just means the behavior will be unpredictable if you use it in a multithread scenario without proper locking; there is nothing in ObservableCollection<T> that will explicitly throw an exception if you do this.

However, the CollectionView class does have thread affinity, which is why you can't add items to an ObservableCollection<T> from a different thread if there is a CollectionView attached to it (which happens, for instance, when you bind an ItemsControl to the collection). But it's the CollectionView that throws an exception, not the ObservableCollection<T>...

Take the following code:

var list = new ObservableCollection<string>();
// var view = CollectionViewSource.GetDefaultView(list);
ThreadPool.QueueUserWorkItem(_ => list.Add("foo"));

It executes without throwing an exception, but if you uncomment the line that creates the CollectionView, it will throw a NotSupportedException:

This type of CollectionView does not support changes to its
SourceCollection from a thread different from the Dispatcher thread.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文