函数隐私和单元测试Haskell

52

你如何处理Haskell中的函数可见性和单元测试?

如果您将模块中的每个函数都导出,以便单元测试可以访问它们,那么您会冒险让其他人调用不应该在公共API中的函数。

我考虑使用{-# LANGUAGE CPP #-}然后用#ifdef包围导出部分:

{-# LANGUAGE CPP #-}

module SomeModule
#ifndef TESTING
( export1
, export2
)
#endif
where

有没有更好的方法?


可能是 https://dev59.com/bHVD5IYBdhLWcg3wRpaX 的重复问题。 - Raedwald
2个回答

78

通常的约定是将您的模块分为公共部分和私有部分,即:

module SomeModule.Internal where

-- ... exports all private methods

然后是公共API

module SomeModule where (export1, export2)

import SomeModule.Internal

那么在测试和其他需要获得内部实现的地方,你可以导入SomeModule.Internal

这个想法是,库的用户永远不会无意中调用私有 API,但如果他们知道自己在做什么(例如调试),就可以使用它。与强制隐藏私有 API 相比,这大大增加了您的库的可用性。


2
这会影响内联(编译时优化)吗?阅读 https://www.haskell.org/haskellwiki/Performance/GHC#Inlining 看起来是会的...所以你可以写单元测试或者进行优化?(请,有人告诉我我错了!) - tlo
1
如果担心这种技术会禁用一次内联优化,请注意,您仍然可以使用显式内联来确保它发生。 - Jules
2
对于任何想要在 Haskell-Stack 中使用这些建议的人,为了创建 SomeModule.Internal 模块,您需要创建一个适当的目录结构 - 参见这个问题 - hnefatl

9

进行测试时,通常会在cabal项目文件中将应用程序分为库、生产可执行文件和test-suite可执行文件,以测试库函数,因此测试断言函数被保留。

对于外部函数的可见性,您需要在库模块之间划分“exposed-modules”部分和“other-modules”部分。


以下是一个 Cabal 包的示例,其中包含库和可执行文件:http://www.haskell.org/cabal/users-guide/developing-packages.html#configurations - Emmanuel Touzery
测试套件是否可以包含针对“other-modules”部分中的模块的测试?在不向外部客户端公开内部单元测试的情况下进行单元测试听起来非常理想。 - Blaisorblade
3
@Blaisorblade 是的,测试套件访问other-modules模块的方法是在cabal文件中指定hs-source-dirs: src, tests。换句话说,src也会在测试套件中编译。缺点是您需要将源代码编译两次:正常编译和测试编译。但这是我所知道的最好的方法。 - Emmanuel Touzery

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接