如何测试onLoad/onAttach与onUnload/onDetach的正确行为?
问题描述
在R包的.onLoad()中定义了全局状态设置函数,.onUnload()中实现了状态重置逻辑,但这套逻辑和devtools工具不兼容——运行devtools::document()或devtools::test()时,会触发websocket包的异常警告。想解决以下问题:
- 如何在测试套件中捕获这类问题?
- 是否必须脱离
testthat进行测试? - 求testthat中启动新R进程测试的示例,或其他可行方案。
解决方案
无需脱离testthat:用独立进程隔离测试
devtools的命令会在当前R会话反复加载、卸载包,全局状态残留是触发websocket警告的核心原因。解决思路是在全新的R进程中测试包的加载/卸载全流程,避免当前会话的状态污染。testthat可以结合callr包实现这个需求,具体示例如下:
步骤与代码
- 先安装依赖的
callr包:
install.packages("callr")
- 在测试目录下新建测试文件
tests/testthat/test-load-unload.R,写入以下测试代码:
test_that("包加载卸载无websocket警告", { # 启动独立R进程,执行加载-操作-卸载流程 proc_result <- callr::r(function() { # 加载目标包 library(your_package_name) # 调用.onLoad中设置的全局状态函数(模拟实际使用场景) your_global_setup_function() # 卸载包 detach("package:your_package_name", unload = TRUE) # 收集过程中产生的所有警告 as.character(warnings()) }) # 检查是否存在websocket相关警告 has_ws_warning <- any(grepl("websocket", proc_result, ignore.case = TRUE)) expect_false(has_ws_warning, info = "加载/卸载包时出现了websocket异常警告") })
逻辑说明
callr::r()会启动一个完全干净的R会话,和当前测试环境彻底隔离,完美复现用户实际使用或devtools触发的加载/卸载场景。- 在新进程中完整执行加载、状态操作、卸载流程,收集所有警告后返回主进程,再验证是否存在目标警告。
备选:手动脚本调试方案
如果需要更灵活的调试,可以写独立R脚本手动验证:
# 脚本路径:tests/load-unload-check.R # 加载包 library(your_package_name) # 执行全局状态操作 your_global_setup_function() # 卸载包 detach("package:your_package_name", unload = TRUE) # 打印所有警告信息 cat("捕获到的警告:\n") print(warnings())
运行脚本的命令(终端执行):
Rscript tests/load-unload-check.R
直接查看输出即可确认是否存在websocket警告,适合快速定位问题。
关键注意点
- 这类问题的本质是同一会话内多次加载卸载包导致的全局状态残留,只有用独立进程测试才能精准复现devtools触发的场景。
- 用
callr结合testthat的方案,既保留了testthat的测试框架优势,又能有效隔离状态污染,不用脱离testthat。
内容的提问来源于stack exchange,提问作者wdkrnls
相关产品推荐
相关产品推荐

