如何使NUnit运行未由模块导出的F#测试

use*_*059 7 f# nunit

我在F#中编写了一个大型模块,恰好有一个简单的界面.该模块包含大约1000行代码,50个单元测试,并只导出一个易于理解的功能.

接下来要做的就是编写一个小的fsi文件.这有许多优点,包括防止命名空间污染,为文档提供明显的位置,确保如果有人决定重用内部,他们将有动力干净地将它们分解出来,毫无疑问,许多其他人.我相信我在这里向合唱团讲道,但仍然觉得值得解释为什么我认为有fsi文件是有帮助的.

现在问题.NUnit将不再运行单元测试,谴责声称它们不公开.那么,那将是因为它们不以任何方式成为界面的一部分.我并不特别希望将它们添加到界面中,尽管如此,因为它意味着每次添加另一个测试时都会更新它,并且它会使fsi文件膨胀一个数量级.

我想一个简单的解决方法是将代码移动到其他地方,将其导入到一个很小的.fs文件中,然后转发一个函数.幸运的是,每个人都会认为这只是令人反感.请问有更好的方法吗?

编辑:非常感谢所有回复的人.我赞同这两个答案.我本来想分开赏金,但是因为这似乎不可能(我有点随意)接受Tomas的回答.

Tom*_*cek 6

如果要添加fsi文件以指定源中模块和函数的可见性,则需要包含应公开访问的所有函数的声明.这意味着如果NUnit要求测试是公共函数,则需要将它们包含在fsi文件中.

但是,还有另一种在F#中指定可见性的方法 - fsi您可以只在声明中添加适当的可见性修饰符,而不是使用文件.这样,您可以隐藏所有实现细节并仅导出main函数和测试:

namespace MyLibrary
open NUnit.Framework

// Implementation details can be in this module
// (which will not be visible outside of the library)
module private Internal = 
  let foo n = n * 2
  let bar n = n + 1

// A public module can contain the public API (and use internal implementation)    
module public MyModule = 
  open Internal
  let doWork n = foo (bar n)

// To make the tests visible to NUnit, these can be placed in a public module
// (but they can still access all functions from 'Internal')
module public Tests = 
  open MyModule

  [<Test>]
  let ``does work for n = 1``() = 
    Assert.Equals(doWork 1, 4) 
Run Code Online (Sandbox Code Playgroud)

与使用fsi文件相比,这样做的缺点是您没有单独的文件,只能很好地描述API的重要部分.但是,您将获得所需内容 - 隐藏实现细节并仅显示单个函数和测试.