2016-03-08 44 views
2

我想用FSUnit(特别是它的Xunit分支)来测试F#中两个集合的平等,但迄今为止发生了可怕的失败。用FSUnit.Xunit测试集合

我有一个函数返回特定结构的数组,并且想要测试返回的数组是否正确。我正在测试的代码是在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都是全新的,所以我可能会错过一些绝对明显的东西。

编辑:,实际工作更好地在评论(比较,而不是对象的字符串表示自己)认为,虽然我将使用在我实际的代码,我仍然希望真正解决我的问题上面的一种解决方法。

+0

不是我有一个答案,但可能会帮助其他人看这个。是使用XUnit的一个要求还是你可以改变使用NUnit? –

+0

我可以在没有任何问题的情况下更改为NUnit,但更喜欢FSUnit本机解决方案。 – Petrroll

+0

是否有任何理由不能将结构转换为可打印格式并比较可打印格式或编写自定义比较函数并调用该函数。我所从事的一个项目使用了带有NUnit的FSUnit,并且我们以打印的形式对AST进行了大量比较。请参阅[测试](https://github.com/jack-pappas/fsharp-logic-examples/blob/master/FSharpx.Books.AutomatedReasoning.Tests/equal.fs) –

回答

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)|]修复了此问题。


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

2

尽管无法从C#代码轻松返回F#列表,但有一种选择是返回数组。这些具有结构相等,所以你可以简单地比较它们以确定它们是否彼此相等:

open System.Linq 

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

这两个数组是相等的:

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

如果你不想返回数组,你也可以返回IEnumerable<T>,并转换为任意列表或数组中的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

+0

那么测试失败了呢?我的意思是这些值是相同的,并且ParseExpression返回一个数组?考虑这个问题,它看起来好像“我将结果转换为数组不是一个数组,而是一个包含tupple的单元素长阵列(只是根据测试消息猜测)......将研究 – Petrroll

+0

@Petrroll在我的回答中,数组中的* values *是结构相等的int值,因此在F#中所有其他值类型,记录类型和区别联合,但大多数.NET对象不会。默认情况下,.NET对象的引用相等。[My Pluralsight course](http://bit.ly/unittestingwithfsharp)有更多详细信息。 –

+0

是的,我知道,但数组是一个结构数组,结构体有一个默认的EqualityComparer然后(尽管如果结构包含一个ref字段槽慢反射)比较每个成员字段使用他们的相等比较器。而我的stucts成员字段是值类型或字符串(它也有一个覆盖相等比较器)...所以应该不是问题 – Petrroll