我在哪里定义任意实例?

Where do I define Arbitrary instances?

我不知道在哪里为我的数据类型定义 Arbitrary 实例。如果我把它 放在 包中,那么包就不必将 QuickCheck 作为依赖项。如果我把它 放在 测试中,那么其他包就不能使用这个实例。如果我把它放在一个单独的 test-utils 包中,那么测试 also 必须放在一个单独的包中,所以它是一个孤立实例并且 also stack test --coverage 不起作用。

还有哪些其他选择?

我通常会选择单独的包选项 — 但我不使用 stack test --coverage。感谢您向我介绍它!

(编辑:我可能会这样做,然后仅对 运行 stack test --coverage --flag thepackage:arbitrary 使用测试标志选项,这样其他人就不必处理这些标志了。)

可能也值得在 stack 问题跟踪器上提出 --coverage 问题,因为在这种情况下覆盖率检查会起作用。

您要求其他选项 - 最好的可能是测试标志。

一个测试标志

可以在您的 cabal 文件中定义一个标志(默认为 false),如果选择该标志,它将只构建具有您的 QuickCheck 依赖项的模块。

将需要的代码放在目录arbitrary中(例如)。然后将以下等效内容添加到 package.yaml(第一个片段)或 the-library.cabal(第二个片段)文件的相关部分:

flags:
  arbitrary:
    description: Compile with arbitrary instances
    default: false
    manual: true

library:
  ⁝
  when:
  - condition: flag(arbitrary)
    dependencies:
    - QuickCheck
    source-dirs:
    - arbitrary
flag arbitrary
  description: Compile with arbitrary instances
  manual: True
  default: False

library
  ⁝
  if flag(arbitrary)
    hs-source-dirs:
      arbitrary
    build-depends:
      QuickCheck

然后,想要使用这些实例的软件包应该在它们的 stack.yaml(第 1 个)或 cabal.project(第 2 个)文件中添加以下内容:

flag:
  the-library:
    arbitrary: true
constraints: the-library +arbitrary

但是有一个小问题……目前该库无法仅在其测试套件中依赖 +arbitrary 版本,除非它也定义了这样的标志。这可能是一个值得付出的代价。

注意:我还没有测试下游包装。

Ivan Milenovic's blog 作为初始资源很有用。

DerivingVia/Generic 个实例

可能还有另一种可能,现在GHC 8.6已经发布,DerivingViaBlöndal, Löh & Scott (2018) 中有一个针对 Arbitrary 个实例的案例研究。

您将创建新类型包装器,并为这些新类型实施 Arbitrary

它并没有像现在这样完全避免问题。但是您可以为这些新类型实现 Generic,使使用 generic-arbitrary 派生的实例与您想要的相匹配。


可能还有一些其他的选择。特别是,QuickCheck 的依赖性实际上并没有那么重。还有其他测试库。另外,请注意,已经有一些关于将类似 Arbitrary 的类型类分离到独立库中的讨论。

我也建议使用内部库,但这不允许其他包使用您的实例。