tfc*_*tfc 7 haskell unit-testing inotify cabal
简而言之,我的问题是“如何在 cabal 管理的多库 haskell 项目存储库中获得快速保存重新测试工作流程?”
\n我已经尝试了一些事情并做了一些研究。在了解更多详细信息之前,请先查看典型的项目存储库结构,然后将问题分解为更多详细信息:
\n我从事多个 Haskell 项目,这些项目通常具有以下形式:
\n.\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 foo\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 foo.cabal\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 src\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 unit-test\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 ...\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 bar\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 bar.cabal\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 src\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 unit-test\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 ...\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 baz\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 baz.cabal\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 src\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 unit-test\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 ...\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 stack.yaml\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 cabal.project\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 nix\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 ...\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 ...\nRun Code Online (Sandbox Code Playgroud)\n该cabal.project文件如下所示:
packages: \n foo\n bar\n baz\n ...\ntests: True\nrun-tests: True\nRun Code Online (Sandbox Code Playgroud)\n堆栈文件包含基本相同的项目列表和 LTS ID,因此我可以只使用IOHK\'s haskell.nixstackProject中的 nix 函数来为自己提供一个包含 cabal 等的 nix shell。(这个问题更多的是关于阴谋集团的处理,所以我认为这里的这段文字只是一个背景说明,我认为与这个堆栈溢出问题无关。)
这个设置允许我在项目中的任何地方运行cabal test all,这很棒。这是我在关闭下一个 git 提交之前查看是否破坏了任何内容的简单方法。
在我到达 nix 之前,我使用了stack build/test --watch这很好,因为我现在可以打开一个 shell,在我更改任何地方的任何内容后,它总是重新测试并重建整个项目。
这可以通过以下方式模拟inotify:
while true; do \n inotifywait -e modify -r ./; \n cabal test all\ndone\nRun Code Online (Sandbox Code Playgroud)\n这并不是很快,但也能完成工作。
\n在我了解GHCID后,我对它的速度如此之快感到惊讶。\n它也很容易与cabal repl.
不幸的是(这个问题也被提到,但在评论中没有得到解答:How to run test suite in ghcid with cabal?),GHCID 可以在一个特定的单元测试套件上运行,并且不会检测单元测试所假定的库上的更改去检查。(我认为将所有库模块放入 cabal 文件中的单元测试描述中是一种丑陋的黑客行为,我宁愿避免这种情况)
\n另外,我似乎无法像或那样在整个存储库上运行 GHCID 。\nGHCID 的极速是我在工作流程中真正想要的东西。cabal test allstack test --watch
cabal是一个在堆栈之前就已经存在很长时间的工具,人们如何在他们的多库存储库上工作,以快速概述他们在编辑多个库中的多个文件后破坏的所有测试用例?如果GHCID方式不好用,有什么办法呢?
我当前的解决方法是嵌套ghcid调用:
ghcid --target=$LIBRARY_NAME --run=":! ghcid --target=$TEST_SUITE --run"
Run Code Online (Sandbox Code Playgroud)
当测试发生变化时,最里面的部分ghcid会重新编译并重新运行测试,最外面的部分会在库源发生变化时重新编译库并重新启动最里面的一个。
我使用带有堆栈的脚本,如下所示:
ghcid -c="stack ghci <test-suite>.hs" -T="main" --warnings $@
Run Code Online (Sandbox Code Playgroud)
这意味着:
ghcidstack ghci而不是香草ghcighcimain(从测试套件)ghcicabal repl例如,您可以轻松地使用它来代替stack ghci.
这样做有以下缺点:
package.yaml/the cabal 文件中提取。main来调用它们。:!stack test我之前通过使用as 命令来解决这些问题,该命令运行所有测试套件,但由于这是通过命令行发出的而不是加载到 ghci 中,因此测试运行速度要慢得多。此外,它没有对测试的修改进行热重载。
底线是:为了获得 ghcid 的好处,需要告知 ghcid 要查看哪些源文件。任何通过 shell 命令重新加载 ghcid 都需要 ghci 完全重新加载和重新编译,而不是利用 ghci 的快速热重加载功能。如果此信息存储在构建系统配置文件中,则您的构建系统需要与 ghcid 集成(缺少自定义脚本)。我的猜测是这对于 cabal 来说太低级了,但我已经打开了堆栈的功能请求。如果您想看到这种情况发生,请在此处添加评论或反应!