具有用于编译时检查的示例值是否常见?它们应该放在代码中的什么位置?

问题描述

我有一个相当复杂的数据类型和记录结构,对于不熟悉代码库的人来说,仅通过查看生产代码并不容易理解。

为了理解它,我创建了这种具有两个优点的虚拟函数:1. 它们在编译时被检查 2. 它们用作某种文档,展示了整体结构如何的示例数据类型和记录混合在一起:

-- benefit 1: a newcomer can quickly make sense of the type system
-- benefit 2: easier to keep track of how the types evolve because of compile-time checking
exampleValue1 :: ApiResponseContent
exampleValue1 = ApiOnlineResponseContent [
        OnlineResultRow (EntityId 10) [Just (FvInt 1),Just (FvFloat 1.5),Nothing],OnlineResultRow (EntityId 20) [Just (FvInt 2),Nothing,Just (FvBool True)]
    ]

唯一让我感到困扰的是,将它们放在生产代码中感觉有点尴尬,因为它们显然是死代码。然而,它们也不是测试,它们只是编译时检查的示例,说明如何从复杂的嵌套类型将值组装在一起。因此,它们显然不属于生产代码,但也不完全属于测试。

这种编译时示例是常见的做法吗?它们应该放在代码库中的什么位置?

解决方法

您是否考虑过包含 examples as part of Haddock documentation


否则,有一种思想流派试图将测试重新构建为示例。您可以在 Gerard Meszaros 的单元测试工作中找到a brief mention。 Dan North 也多次使用类似的语言,但通常很难追踪他对此类想法的多次迭代。他倾向于“在公共场合思考”——这是一种这样的反思:

I call this development,using example-guided design

我知道被问到的例子并不是那样的。不过,我认为它更适合测试代码而不是生产代码。

如果您将示例放在生产代码中,那么您实际上将其作为库的 API 的一部分(如果您要发布库)。这意味着更改示例将构成重大更改。这对我来说似乎不对。

在 BDD/DDD 社区中,有很多强调将测试作为示例,从自动化测试作为文档的意义上来说也是如此。如果没有 Haddock 文档,我会考虑将示例放在测试代码中,作为文档。有时我会通过简单地将此类“空测试”放在名为 examples 的文件中来实现这一点,可能会在顶部添加一些注释以说明该文件中的代码有助于学习而不是验证行为。

它避免了在生产代码中引入冗余破坏性更改的风险,并且在概念上似乎更合适。

,

我不同意这些不是测试。甚至“此示例是否编译”也可以视为测试,但您可能也可以使用它们来实际测试某些功能。

因此,将这些定义放在您的测试套件中,并使用它们对实际处理这些值的函数进行单元测试。

,

我见过的容纳此类示例的主要约定是包含 ….Tutorial 模块,例如 Dhall.TutorialClash.Tutorial,或并行 …-tutorial 包,例如 {{ 3}}。

这些包含 Haddock 文档,按照线性顺序进行组织,以及像您这样的示例定义。

通过很好的例子,我发现除了类型和参考文档之外,这个约定对于理解和试验新包非常有帮助。在 Hackage 上浏览包时也很容易发现,特别是如果您确保参考和 README 链接到教程以获得更长的解释。

这些模块可以只编译为基本验证,但是对文档进行更多机器验证是非常有价值的,所以我认为将它们链接到测试套件(例如 lens-tutorial)中作为单元测试的示例会更好(hspec) 或属性测试 (HUnit/QuickCheck),或将它们组织为文档测试 (hedgehog)。

除了 GHC 的代码覆盖率工具之外,doctest 还可以帮助识别未经测试的示例。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...