【发布时间】:2014-07-12 07:24:11
【问题描述】:
我对 F# 非常陌生,并且在 F# for fun and profit(优秀网站)上使用堆栈计算器。我试图弄清楚如何进行测试项目和课程。我有一个使用这种方法的测试类:
open NUnit.Framework
open FSharpDoodles.MainProgram
[<TestFixture>]
type ProgramTests()=
[<Test>]
member self.FirstTest()=
// Create some stacks
let EMPTY = StackContents []
let try1 = push 1.0 EMPTY // OK
let try2_partial = push 1.0 // OK
let try2 = try2_partial EMPTY // OK - does same as ONE below
let stackWith1 = ONE EMPTY // FAILS: ONE is null
()
它正在测试的代码是这样的:
module FSharpDoodles.MainProgram
type Stack = StackContents of float list
let push x (StackContents contents) =
StackContents ( x::contents )
let ONE = push 1.0
所以,如果我正在调用一个函数并获取一个值(调用推送),它就可以工作。如果我在类 (try2_partial) 中创建一个部分应用的函数,那就可以了。但是当我引用返回一个部分应用的函数的 ONE 时,ONE 为空。
这是为什么呢?
故事的其余部分
我使用 NCrunch 作为我的测试运行器。完全有可能是它引起了问题。
编辑
按照 John 的建议,我在 FSI 中尝试过这个并遇到了同样的问题。下面是同一个测试代码的渐进式应用:
open FSharpDoodles.MainProgram
let EMPTY = StackContents [];;
val EMPTY : FSharpDoodles.MainProgram.Stack = StackContents []
> let try1 = push 1.0 EMPTY;;
val try1 : Stack = StackContents [1.0]
> let try2_partial = push 1.0;;
val try2_partial : (Stack -> Stack)
> let try2 = try2_partial EMPTY;;
val try2 : Stack = StackContents [1.0]
> let stackWith1 = ONE EMPTY;;
System.NullReferenceException: Object reference not set to an instance of an object.
at <StartupCode$FSI_0006>.$FSI_0006.main@()
Stopped due to error
我在 Tools|Options -> F# Interactive, F# Interactive options 下参考了 FSI 的 SUT。我使用了 -r 并在 debug\bin 中引用了程序集。
正如我所提到的,我对 F# 的东西非常陌生,我可能会犯一些与我如何组合两个模块有关的非常菜鸟的错误。
更新 2
根据 John 的评论,我尝试将代码从 .exe 移动到 .dll(库)。它工作得很好。因此,问题与引用 .exe 有关。所以现在的问题变成了为什么这会有所不同(exe vs dll)?
【问题讨论】:
-
我的猜测是测试运行程序没有正确调用模块设置,导致
ONE未初始化。您可以通过在 FSI 中运行代码来测试这一点。也许尝试不同的测试运行器? -
这听起来很合理。我刚刚使用 TestDriven.NET 执行了这个测试,它按预期工作;调试器单步执行表明
stackWith1和ONE都是正确的值(而不是空值)。 -
当您尝试评估
ONE时,您会在 fsi 中得到什么? -
好的,这与它是一个EXE有关。我将代码移到了一个库中,它运行良好。感谢约翰提出了正确的问题。 :D 如果有人知道为什么这会有所不同(exe 与 dll)或有指向此参考的链接,请将其发布为答案。
-
之前没有看到评论回复,但不同的是,当代码编译为exe时,F#会插入一些早期运行的初始化代码。当您引用 exe 时,此代码不会运行。编译为 dll 可以解决这个问题。