我的R包修改了远程数据库中的数据,我想用testthat
编写一些测试。
我知道我可以模拟数据库,但是我只想使用我们的一个开发数据库。
如何确保所有需要连接的测试都可以使用数据库连接,同时确保已创建的所有连接均已销毁?显然应该在setup
中进行连接,而在teardown
中断开连接,但是我没有进行管理。
我试图将以下代码放入tests/testthat.R
或帮助文件tests/testthat/helper-_
中,无济于事。
setup({
# db_connect is just a basic wrapper around RMariaDB::dbConnect with logging
db_con <- db_connect(conf$database, loglevel = "none")
})
teardown({
# db_connect is just a basic wrapper around DBI::dbDisconnect with logging
db_disconnect(db_con = db_con, loglevel = "none")
})
我的初始测试是:
tests
├── testthat
│ ├── helper-_.R
│ ├── test-connect.R
│ └── test-questions.R
└── testthat.R
在第一个文件(所有测试均通过)之后,我得到Error in DBI::dbDisconnect(db_con) : object 'db_con' not found
,它指示拆解正在发生,但未找到db_con
。
此后,所有需要db_con
的测试都以object 'db_con' not found
失败。
是否需要为每个需要db_con
的文件创建一个帮助文件?还是我必须显式地获取公共帮助文件?
有没有一种方法可以在某个地方建立一次连接并使其可用于所有测试并在最后销毁?
答案 0 :(得分:1)
编辑:test-connect_init中的dbDisconnect。这种结构在从数据库中(一次或几次)获取数据的工作流程中效果最好。
免责声明:以下内容已通过Impala成功测试。
我选择了采购方式,创建了一个在脚本和测试中调用的connect_init.R函数:
R
├── utils
| ├── connect_init.R
| ├── df_import.R
├── clean
| ├── data_clean.R
tests
├── testthat
│ ├── test-connect.R
│ ├── test-import.R
│ └── test-clean.R
└── testthat.R
connect_init <- function(params) DBI::dbConnect(...)
[...]
con <- connect_init(params)
rqt <- "select * from db.tab"
dframe <- DBI::dbGetQuery(conn = con, rqt)
# --- when import finished
DBI::dbDisconnect(con)
context("test-connect")
test_that("connexion to Impala doable",
res <- mypkg::connect_init(params)
testthat::expect_true(attributes(res)$class[1] == "Impala")
DBI::dbDisconnect(res)
})
context("test-import")
test_that("import from Impala doable", {
res <- mypkg::df_import(paramsbis)
testthat::expect_s3_class(object = res, class = "data.frame")
testthat::expect_true(nrow(res) > 0)
})
然后在其他测试中使用时打开和关闭连接。我对以其他方式测试此反馈以及如何改进此部分的反馈非常感兴趣。
我们应该存储最少的样本数据,以便在出现网络/数据库问题时非连接测试不会失败吗?
答案 1 :(得分:0)
从testthat
docs
setup()
块中的代码在干净的环境中立即运行
我相信这意味着,如果您要保存在setup
环境中创建的所有对象,则需要将它们放置在全局环境中
setup({
db_con <- db_connect(conf$database, loglevel = "none")
assign("db_con", db_con, envir = .GlobalEnv)
})
然后在您的teardown()
方法中,它将能够找到连接
teardown({
db_disconnect(db_con = db_con, loglevel = "none")
# Can also remove it from the global environment after disconnect
rm(db_con, envir = .GlobalEnv)
})
搞砸全球环境并不是理想的选择,但是只要您仔细命名并在完成后将其删除,就不成问题。
似乎setup()
设计用于读取/写入临时文件/临时目录,而不是用于创建供所有测试使用的全局对象,但我可能会误会。
我在研究这个问题时遇到的有用的例子:https://github.com/ropensci/Rpolyhedra/blob/3675a3a6eb8b2807f26fb2ebc929b9f5072681db/tests/testthat/test_package_lib.R#L7