Cabal测试覆盖率报告为空及多报告文件问题咨询
Haskell Cabal 覆盖率报告问题解析
项目背景
项目结构
.git src/ exe/ Main.hs lib/ ModuleA/ ModuleB/ UnitTests/ UnitTests.hs MainLib.hs giter.cabal
可执行文件代码(src/exe/Main.hs)
import qualified MainLib main :: IO () main = MainLib.main
Cabal 配置片段(giter.cabal)
library import: shared-properties exposed-modules: MainLib other-modules: ModuleA ModuleB build-depends: , brick , directory , fsnotify hs-source-dirs: src/lib executable giter import: shared-properties main-is: Main.hs other-modules: build-depends: , giter , base , brick hs-source-dirs: src/exe test-suite giter-test type: exitcode-stdio-1.0 hs-source-dirs: src/lib main-is: UnitTests/UnitTests.hs default-language: Haskell2010 other-modules: ModuleA ModuleB build-depends: , base , directory , HUnit , QuickCheck
问题现象
执行命令 cabal new-test all --enable-coverage 后测试全部通过,但生成的两个HTML覆盖率报告均无有效数据,示例如下:
module Top Level Definitions Alternatives Expressions % covered / total % covered / total % covered / total Program Coverage Total - 0/0 - 0/0 - 0/0
问题解答
1. 覆盖率报告缺失数据的原因
- 测试套件未复用库的插桩编译产物:测试套件
giter-test的hs-source-dirs设为src/lib,并直接将ModuleA、ModuleB列为other-modules,这会让Cabal重新编译这些模块且未启用覆盖率插桩。测试运行的是无插桩的模块,自然无法收集覆盖率数据。 - 库目标未启用覆盖率编译:默认情况下,
--enable-coverage仅为测试套件启用覆盖率插桩,库目标需要显式开启,否则测试依赖的库模块没有覆盖率收集能力。
2. 生成两个报告的原因
- 命令中的
all会触发所有目标的覆盖率收集,包括库目标和测试套件目标,两者各自生成报告。 - 你的测试套件配置直接编译
src/lib下的业务模块,相当于独立构建了一个包含这些模块的二进制,而非依赖已编译的库,这会额外生成一份测试套件自身的覆盖率报告。
修复方案
调整测试套件配置
修改test-suite giter-test部分,让它依赖库目标giter,仅编译测试代码:
test-suite giter-test type: exitcode-stdio-1.0 hs-source-dirs: src/lib/UnitTests # 仅指向测试代码目录 main-is: UnitTests.hs default-language: Haskell2010 build-depends: , base , directory , giter # 依赖库目标,复用带插桩的业务模块 , HUnit , QuickCheck
全局启用覆盖率
运行测试时显式开启库和测试的覆盖率:
cabal new-test giter-test --enable-coverage --enable-library-coverage
或者在项目根目录创建cabal.project文件,添加全局配置:
coverage: True library-coverage: True
内容的提问来源于stack exchange,提问作者Refael Sheinker
相关产品推荐
相关产品推荐

