使用R中covr时package_coverage与file_coverage结果不一致问题
可能的原因
1. 网络环境差异
package_coverage() 可能在无网络的环境(如CI流水线)中运行,导致 readLines("http://scihub.copernicus.eu", n=1) 调用失败,is_online 被设为 FALSE。此时函数会跳过 if (is_online) 块内的所有代码(检查sen2r安装状态、版本等逻辑),未执行的代码拉低了整体覆盖率。而 file_coverage() 运行在有网络的本地环境,is_online 为 TRUE,执行了更多分支,覆盖率自然更高。
2. 依赖包sen2r的安装状态不一致
如果运行 package_coverage() 的环境未安装 sen2r,即使网络正常,函数会在检测到 sen2r 未安装时提前返回 FALSE,跳过版本检查的代码。而 file_coverage() 运行的环境安装了 sen2r,这部分代码被执行,提升了覆盖率。
3. 函数在包加载阶段被调用(covr未跟踪)
若 check_scihub_access 在包加载时被触发(比如在 .onLoad() 或 .onAttach() 中),此时covr还未启动代码跟踪,这部分执行不会被计入覆盖率。而 file_coverage() 仅在测试阶段调用该函数,此时covr已激活跟踪,所以能统计到这部分执行。covr::in_covr() 返回 FALSE 恰好印证了这一点——函数被调用时covr的跟踪机制尚未生效。
4. covr版本或配置问题
旧版本的covr可能存在子进程跟踪的bug,导致测试运行时 in_covr() 无法正确识别covr环境,进而影响覆盖率统计。或者 package_coverage() 默认使用 callr 子进程运行测试,环境变量传递异常使得covr跟踪未生效。
解决办法
- 模拟网络与依赖环境:使用
testthat::with_mock()模拟网络请求和依赖包状态,确保覆盖函数的所有分支。例如:
test_that("SCIHUB available with mocked dependencies", { with_mock( readLines = function(...) TRUE, system.file = function(package, ...) "/path/to/sen2r", utils::packageVersion = function(package) package_version("1.6.0"), expect_true(check_scihub_access()) ) with_mock( readLines = function(...) stop("No internet"), expect_false(check_scihub_access()) ) with_mock( readLines = function(...) TRUE, system.file = function(package, ...) "", expect_false(check_scihub_access()) ) with_mock( readLines = function(...) TRUE, system.file = function(package, ...) "/path/to/sen2r", utils::packageVersion = function(package) package_version("1.4.0"), expect_false(check_scihub_access()) ) })
统一测试环境依赖:在运行
package_coverage()的环境中安装sen2r,保证与本地测试环境一致。调整函数调用时机:避免在包加载阶段调用
check_scihub_access,仅在实际需要时(如测试或用户调用)执行,确保covr能跟踪到代码执行。升级covr版本:更新到最新版covr,修复可能存在的跟踪bug。
内容的提问来源于stack exchange,提问作者Micha

