F# Observable - 将事件流转换为列表

F# Observable - Converting an event stream to a list

我正在编写一个单元测试来验证从 class 触发的事件。我遵循了标准 "IEvent<_>, Publish, Trigger inside an FSharp type" 模式。

你能推荐 "functional" 实现该目标的方法吗?

以下是我能想到的选项:

  1. 将事件流转换为字符串列表,并将该列表与预期列表进行比较
  2. (不确定有没有办法)将预期列表转换成事件流,比较两个流

指向被截断的代码的指针将大有帮助。

谢谢!


编辑 1:回答 Mark 的问题:

这是我目前拥有的:

let expectedFiles = [ "c:\a"
                      "c:\a" ]

[<Fact>]
let ``Can find files from a folder`` () =
    let ad = new FileSearchAdapter()
    let foundFiles = ref []
    ad.FileFound 
    |> Observable.scan (fun acc e -> e::acc) [] 
    |> Observable.add (fun acc -> foundFiles := acc)
    ad.FindFiles @"c:\a"
    Assert.Equal<string list>(expectedFiles, !foundFiles)

我觉得这里的问题是 [a] 引用单元格的使用 [b] observable.add 本质上是覆盖每个事件的引用。

是否有实现相同功能的方法?

事件都是关于副作用的,因此尝试使其全部功能的意义有限。

(是的:您可以构建反应式系统,其中不可变的事件数据流经系统,沿途被过滤和聚合,但在源头,引发事件是副作用。)

考虑到单元测试测试的是独立于其依赖项的单元,测试事件是否正确引发,测试了系统的隔离 'un-functional' 部分,所以我不认为你 以函数式方式完成。

这里有一个更简单的选择:

open System.Collections.Generic

let ``Can find files from a folder`` () =
    let ad = new FileSearchAdapter()
    let foundFiles = List<string>()
    ad.FileFound.Add(fun (sender, args) -> foundFiles.Add args)

    ad.FindFiles "c:\a"

    let expectedFiles = [ "c:\a"; "c:\a" ]
    expectedFiles = (foundFiles |> Seq.toList)

(这个测试函数只是 returns bool 的一个普通函数,但我相信你知道如何将它转换为单元测试。)