[英]Run testthat test in separate R session (how to combine the outcomes)
I need to test package loading operations (for my multiversion package ) and know that unloading namespaces and stuff is dangerous work.我需要测试 package 加载操作(对于我的多版本 package )并且知道卸载命名空间和东西是危险的工作。 So I want to run every test in a fresh R session.所以我想在新的 R session 中运行每个测试。 Running my tests in parallel does not meet this demand since it will reuse slaves, and these get dirty.并行运行我的测试不能满足这个需求,因为它会重用从站,并且这些会变脏。
So I thought callr::r
would help me out.所以我认为callr::r
会帮助我。 Unfortunately I am again stuck with the minimally documented reporters it seems.不幸的是,我再次被记录在案的记者所困。
The following is a minimal example.以下是一个最小的示例。 Placed in file test-mytest.R
.放在文件test-mytest.R
中。
test_that('test 1', {
expect_equal(2+2, 5)
})
reporter_in <- testthat::get_reporter()
# -- 1 --
reporter_out <- callr::r(
function(reporter) {
reporter <- testthat::with_reporter(reporter, {
testthat::test_that("test inside", {
testthat::expect_equal('this', 'wont match')
})
})
},
args = list(reporter = reporter_in),
show = TRUE
)
# -- 2 --
testthat::set_reporter(reporter_out)
# -- 3 --
test_that('test 2', {
expect_equal(2+2, 8)
})
I called this test file using:我使用以下方法调用了这个测试文件:
# to be able to check the outcome, work with a specific reporter
summary <- testthat::SummaryReporter$new()
testthat::test_file('./tests/testthat/test-mytest.R', reporter = summary)
Which seems to do what I want, but when looking at the results...这似乎可以满足我的要求,但是在查看结果时...
> summary$end_reporter()
== Failed ===============================================================================================
-- 1. Failure (test-load_b_pick_last_true.R:5:5): test 1 ------------------------------------------------
2 + 2 (`actual`) not equal to 5 (`expected`).
`actual`: 4
`expected`: 5
== DONE =================================================================================================
...it is only the first test that is returned. ...这只是返回的第一个测试。
-- 1 --
)获取当前使用的记者( -- 1 --
)callr::r
is used to call a testthat block including a test. callr::r
用于调用包含测试的测试块。set_reporter
, but with_reporter
is practically identical.在通话中,我尝试使用set_reporter
,但with_reporter
实际上是相同的。callr::r
call returns the reporter (tried it with get_reporter()
, but with_reporter
also returns the reporter (invisibly)) callr::r
调用返回记者(用get_reporter()
尝试过,但with_reporter
也返回记者(不可见)) Now the returned reporter seems fine, but when setting it as the actual reporter with set_reporter
, it seems that it is not overwriting the actual reporter.现在返回的记者似乎很好,但是当使用set_reporter
将其设置为实际记者时,似乎并没有覆盖实际的记者。
Note that at -- 2 --
, the reporter_out
contains both test outcomes.请注意,在-- 2 --
处, reporter_out
包含两个测试结果。
I am not really sure what I expect it to do, but in the end I want the results to be added to the original reporter (( summary
or) reporter_in
that is, if that is not some kind of copy).我不太确定我期望它做什么,但最后我希望将结果添加到原始报告者(( summary
或) reporter_in
即,如果那不是某种副本)。
One workaround I can think of would be to move the actual test execution outside of the callr::r
call, but gather the testcases inside.我能想到的一种解决方法是将实际测试执行callr::r
调用之外,但在里面收集测试用例。 I think it is neat, as long as you can place these helper functions (see the elaborate example) in your package , you can write tests with little overhead.我认为它很简洁,只要您可以将这些辅助函数(请参阅详细示例) 放在 package中,您就可以编写测试,而且开销很小。
It doesn't answer how to work with the 'reporter' object though...它没有回答如何与“记者” object 一起工作......
test_outcome <- callr::r(
function() {
# devtools::load_all()
list(
check1 = 5+5,
check2 = 'my name'
)
}
)
test_that(test_outcome$desc, {
expect_equal(test_outcome$check1, 10)
expect_equal(test_outcome$check2, 'Siete')
})
Note that from .add_test
to .exp_true
are only function definitions which can better be included in your package so they will be available when being loaded with devtools::load_all()
.请注意,从.add_test
到.exp_true
只是 function 定义,可以更好地包含在 package 中,因此在使用devtools::load_all()
加载时它们将可用。 load_all
also loads not-exported functions by default. load_all
默认情况下还加载未导出的函数。
test_outcome <- callr::r(
function() {
# devtools::load_all()
tst <- list(desc = 'My first test', tests = list())
.add_test <- function(type, A, B) {
# To show at least something about what is actually tested when returning the result, we can add the actual `.exp_...` call to the test.
call <- as.character(sys.call(-1))
tst$tests[[length(tst$tests) + 1]] <<- list(
type = type, a = A, b = B,
# (I couldn't find a better way to create a nice call string)
call = paste0(call[1], '(', paste0(collapse = ', ', call[2:length(call)]), ')'))
}
.exp_error <- function(expr, exp_msg) {
err_msg <- ''
tryCatch({expr}, error = function(err) {
err_msg <<- err$message
})
.add_test('error', err_msg, exp_msg)
}
.exp_match <- function(expr, regex) {
.add_test('match', expr, regex)
}
.exp_equal <- function(expr, ref) {
.add_test('equal', expr, ref)
}
.exp_false <- function(expr) {
.add_test('false', expr, FALSE)
}
.exp_true <- function(expr) {
.add_test('true', expr, TRUE)
}
.exp_match('My name is Siete', 'My name is .*')
.exp_equal(5+5, 10)
.exp_false('package:testthat' %in% search())
return(tst)
},
show = TRUE)
.run_test_batch <- function(test_outcome) {
test_that(test_outcome$desc, {
for (test in test_outcome$tests) {
# 'test' is a list with the fields 'type', 'a', 'b' and 'call'.
# Where 'type' can contain 'match', 'error', 'true', 'false' or 'equal'.
if (test$type == 'equal') {
with(test, expect_equal(a, b, label = call))
} else if (test$type == 'true') {
expect_true( test$a, label = test$call)
} else if (test$type == 'false') {
expect_false(test$a, label = test$call)
} else if (test$type %in% c('match', 'error')) {
with(test, expect_match(a, b, label = call))
}
}
})
}
.run_test_batch(test_outcome)
When moving the functions to your package you would need the following initialize function too.将功能移动到 package 时,您还需要以下初始化 function。
tst <- new.env(parent = emptyenv())
tst$desc = ''
tst$tests = list()
.initialize_test <- function(desc) {
tst$desc = desc
tst$tests = list()
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.