如何在testthat中安全提供敏感API密钥以完成API模拟测试?
解决testthat无法访问本地环境变量的问题
问题背景
我在维护R包scrobbler时,用httptest录制了API请求结果做模拟测试以提升测试覆盖率,但运行testthat快照测试时,因无法读取本地.Renviron文件里的LASTFM_API_USERNAME和LASTFM_API_KEY环境变量导致测试失败。我不能在代码里显式传递这些参数,避免密钥泄露到Git仓库。
可行解决方案
方案1:交互式运行时加载本地.Renviron,非交互式跳过测试
通过interactive()判断当前运行环境,仅在交互式环境下加载本地.Renviron并执行测试,非交互式环境直接跳过:
# 在测试脚本开头加载本地.Renviron(仅交互式环境) if (interactive()) { readRenviron("~/.Renviron") } with_mock_api( { test_that("Output is produced correctly", { skip_if_not(interactive(), "Skipping test in non-interactive environment") local_edition(3) expect_snapshot_value( download_scrobbles(.limit1 = TRUE), style = "deparse" ) }) } )
方案2:使用未提交到Git的本地环境变量文件
- 在包根目录创建
.Renviron.local文件,写入环境变量:
LASTFM_API_USERNAME=your_username LASTFM_API_KEY=your_api_key
- 在
.gitignore中添加.Renviron.local,确保该文件不会被提交到Git; - 在测试脚本开头加载这个本地文件(如果存在):
renviron_local <- file.path(getwd(), ".Renviron.local") if (file.exists(renviron_local)) { readRenviron(renviron_local) } with_mock_api( { test_that("Output is produced correctly", { local_edition(3) expect_snapshot_value( download_scrobbles(.limit1 = TRUE), style = "deparse" ) }) } )
R CMD BUILD默认不会包含.gitignore中排除的文件,因此该文件不会被打包发布,不会泄露密钥。
方案3:测试时临时设置假环境变量
由于httptest模拟阶段会直接使用录制好的响应,不需要真实API密钥,只需临时设置假的环境变量让函数通过参数校验即可:
library(withr) with_mock_api( { test_that("Output is produced correctly", { local_edition(3) # 临时设置假环境变量,仅在当前测试块生效 local_envvar( c(LASTFM_API_USERNAME = "dummy_user", LASTFM_API_KEY = "dummy_key") ) expect_snapshot_value( download_scrobbles(.limit1 = TRUE), style = "deparse" ) }) } )
该方案无需任何本地配置,适合CI等非交互式环境运行测试。
内容的提问来源于stack exchange,提问作者Conor Neilson
相关产品推荐
相关产品推荐

