使用 FParsec 编写的单元测试解析器

Unit Testing Parsers Written Using FParsec

提问人:bookofproofs 提问时间:8/17/2023 最后编辑:Be Brave Be Like Ukrainebookofproofs 更新时间:8/20/2023 访问量:14

问:

我想为我使用 FParsec 编写的解析器生成的抽象语法树编写单元测试。

例如,给定解析器

 open FParsec

 type FooValue = FooValue of int
 let foo: Parser<string,unit> = pstring "foo" 
 let fooValue = pint32
 let p = foo >>. spaces >>. fooValue |>> FooValue.FooValue
 

到目前为止,我发现的唯一测试方法是写作

let resultSuccess = run p "foo 23"
let resultFailure = run p "foo noNumber"

printfn "%O" resultSuccess
printfn "%O" resultFailure

并检查我的 F# 程序是否输出

Success: FooValue 23
Failure:
Error in Ln: 1 Col: 5
foo noNumber
    ^
Expecting: integer number (32-bit, signed)

相反,我更愿意编写一些这样的单元测试:

open FParsec
open Microsoft.VisualStudio.TestTools.UnitTesting

[<TestClass>]
type TestMyParser () =

    [<TestMethod>]
    member this.TestPSucceeds () =
        let actual = run p "foo 23"
        let expected = ......? 
        Assert.AreEqual(actual, expected);

    [<TestMethod>]
    member this.TestPFails () =
        let actual = run p "foo noNumber"
        let expected = ......? 
        Assert.AreEqual(actual, expected);

如您所见,我不知道如何为 FParsec 的抽象语法树的期望值构造有效函数,因此我可以以某种方式将它们与我运行的每个测试的实际结果进行比较。

编辑:如果我能以某种方式将实际结果序列化为字符串并将它们与预期字符串进行比较,那也会对我有所帮助(并且可能会大大简化更复杂的 AST 的比较)。

单元测试 fparsec

评论


答:

0赞 bookofproofs 8/19/2023 #1

我发现了如何做到这一点,它使用起来相对简单。TestMethod 可能如下所示:sprintf

    [<TestMethod>]
    member this.TestPSucceeds () =
        let result = run p "foo 23"
        let actual = sprintf "%O" result
        let expected = """Success: FooValue 23""".Replace("\r","")
        Assert.AreEqual(expected, actual);

将预期的字符串括在 中,后跟函数,确保还可以在此处粘贴更复杂的多行解析器输出。"""Replace("\r","")