【问题标题】:Testing collections with FSUnit.Xunit使用 FSUnit.Xunit 测试集合
【发布时间】:2016-03-09 05:39:03
【问题描述】:

我正在尝试使用 FSUnit(特别是它的 Xunit 分支)在 F# 中测试两个集合的相等性,但到目前为止都失败了。

我有一个函数,它返回一个特定结构的数组,并想测试返回的数组是否正确。我正在测试的代码是用 C# 编写的,所以函数不能返回原生 F# 列表。

我尝试过的最有前途的方法如下:

[<Fact>]
let SimpleTest() = 
    let parser = new ExpressionParser()
    parser.ParseExpression "2" |> should equal [new ParsedItem("2", ParsedItemType.Value)]

...但它导致测试失败,因为:

"Message> FSUnit.Xunit+MatchException: Exception of type 'FsUnit.Xunit+MatchException' was thrown. 

Expected value: Equals [(2)]
Actual: was [2]

我可以看到这是因为本机 F# 列表的类型与本机数组不匹配,但老实说不知道(我也没有在文档中找到任何内容)如何以不同的方式进行操作(除了事先创建本机数组并填充一一...)。

我也尝试了一些其他方法,但它们通常甚至无法编译。


PS:我对 F# 和 Xunit 都是全新的,所以我可能会遗漏一些绝对明显的东西。

编辑: 在 cmets 中建议了一种实际上效果更好的解决方法(比较字符串表示形式而不是对象本身),虽然我将在我的实际代码中使用它,但我仍然希望有一个真正的解决方案我上面的问题。

【问题讨论】:

  • 并不是说我有答案,但可能会帮助其他人看到这个。使用 XUnit 是一项要求,还是可以改为使用 NUnit?
  • 我可以毫无问题地更改为 NUnit,但更喜欢 FSUnit 原生解决方案。
  • 您是否有任何理由无法将结构转换为可打印表单并比较可打印表单或编写自定义比较函数并调用它。我参与的一个项目将 FSUnit 与 NUnit 结合使用,我们以印刷形式对 AST 进行了很多比较。见Tests
  • ParsedItem 类型是否定义了比较?
  • 1) 你说得对,我所说的 FSUnit 原生解决方案是我不想要“切换到 NUnit 并直接使用 Collection.Equal”之类的答案。 2) 比较可打印的表单听起来确实很有趣,但没想到这一点(甚至可以为我省去创建结果数组的麻烦)。 3) 好吧,它是一个结构意味着它有一个默认的 EqualityComparer,但它没有比较器,因为对它们进行排序没有意义。

标签: f# xunit


【解决方案1】:

虽然您不能轻松地从 C# 代码返回 F# 列表,但一种选择是返回数组。它们具有结构相等性,因此您可以简单地比较它们以确定它们是否彼此相等:

open System.Linq

let csharpArray = Enumerable.Range(0, 10).ToArray()
let fsharpArray = [| 0..9 |]

这两个数组相等:

> csharpArray = fsharpArray;;
val it : bool = true

如果不想返回数组,也可以返回IEnumerable&lt;T&gt;,在F#中转换为列表或数组:

> let csharpEnumerable = Enumerable.Range(0, 10);;    
val csharpEnumerable : System.Collections.Generic.IEnumerable<int>

> csharpEnumerable |> Seq.toList = [0..9];;
val it : bool = true

如需更全面地介绍使用 F# 进行单元测试,您可能需要view my Pluralsight course on the topic。

【讨论】:

  • 那么测试是怎么失败的呢?我的意思是值是相同的 ParseExpression 返回一个数组?考虑一下,它看起来好像“我正在计算结果的数组不是一个数组,而是一个包含一个元组的单元素长数组(只是根据测试消息猜测)......将调查那个。
  • @Petrroll 在我的回答中,数组中的 值 是 int 值,它们具有结构相等性。 F# 中的所有其他值类型、记录类型和可区分联合也是如此,但大多数 .NET 对象没有。默认情况下,.NET 对象具有引用相等性。 My Pluralsight course 有更多详情。
  • 是的,我知道,但是该数组是一个结构数组,并且结构有一个默认的 EqualityComparer,然后(尽管如果结构包含一个通过慢反射的 ref 字段)使用它们的相等比较器比较每个成员字段。我的结构上的成员字段要么是值类型,要么是字符串(同样有一个覆盖的相等比较器)......所以这不应该是问题。
  • @Petrroll 如果您发布代码会有所帮助,但是您是否尝试过使用 F# 的 = 运算符比较两个数组?这会告诉你问题出在框架比较上,还是出在 FsUnit 上。
【解决方案2】:

好的,我找到了答案,而且比我想象的要简单。首先,该协议运行良好,问题出在语法上,我没有费心阅读有关如何在 F# 中创建数组的文档,只是猜测它。

有两件事错了。首先[new ParsedItem("2", ParsedItemType.Value)] 不创建数组,而是创建一个列表。这本身对 FSUnit 的 should equal 来说不是问题,但足以使使用 = 的简单结构相等性测试失败。

第二个错误是我没有真正与[new ParsedItem("2", ParsedItemType.Value)] 进行比较,而是与[new ParsedItem("2", ParsedItemType.Value), new ParsedItem("+", ParsedItemType.Operator), new ParsedItem("3", ParsedItemType.Value)] 进行比较,这实际上创建了一个包含一个touple的列表。而这 - 不出所料 - 并没有很好地断言:)。

只需阅读文档并了解应该创建一个数组[|new ParsedItem("2", ParsedItemType.Value); new ParsedItem("+", ParsedItemType.Operator); new ParsedItem("3", ParsedItemType.Value)|] 即可解决此问题。


无论如何,感谢 cmets 和其他答案。虽然他们没有回答我的问题,但他们增加了我对 F# 的了解,并给了我如何测试的新想法:)。

【讨论】:

    猜你喜欢
    • 2020-11-18
    • 2014-05-27
    • 2017-08-16
    • 1970-01-01
    • 2013-05-04
    • 2021-09-08
    • 2019-04-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多