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

时间:2015-05-16 04:56:29

标签: f# functional-programming reactive-programming observable

我正在编写一个单元测试,用于验证从类中触发的事件。我遵循FSharp类型中的标准" IEvent< _>,Publish,Trigger"图案。

你能推荐"功能"实现这一目标的方法?

以下是我能想到的选项:

  1. 将事件流转换为字符串列表,并将该列表与预期列表进行比较
  2. (不确定是否有办法)将预期列表转换为事件流并比较两个流。
  3. 指向剪切代码的指针将非常有用。

    谢谢!

    编辑1:回答Mark的问题:

    这就是我现在所拥有的:

    let expectedFiles = [ "c:\a\1"
                          "c:\a\2" ]
    
    [<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实际上是覆盖了每个事件的引用。

    是否有实现这一目标的功能性方法?

1 个答案:

答案 0 :(得分:4)

事件都是关于副作用的,所以它对于尝试成为所有功能的感觉是有限的。

(是的:您可以构建Reactive系统,其中不可变事件数据流经系统,在此过程中进行过滤和聚合,但在源头,事件被引发,是一种副作用。)

鉴于单元测试单独测试一个单元与其依赖关系,测试正确引发的事件,运行系统中孤立的“无功能”部分,所以我不认为你有< / em>以功能方式完成。

这是一个更简单的选择:

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\1"; "c:\a\2" ]
    expectedFiles = (foundFiles |> Seq.toList)

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