首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在单独的R会话中运行测试(如何组合结果)

在单独的R会话中运行测试(如何组合结果)
EN

Stack Overflow用户
提问于 2021-12-30 09:27:51
回答 1查看 90关注 0票数 2

我需要测试包加载操作(对于我的多版本包),并且知道卸载名称空间和其他东西是一项危险的工作。所以我想在一个新的R会话中运行每一个测试。并行运行我的测试并不能满足这一需求,因为它会重用奴隶,而这些会变得很脏。

所以我想callr::r会帮我的。不幸的是,我又一次被那些很少被记录在案的记者们困住了。

下面是一个很小的例子。放置在文件test-mytest.R中。

代码语言:javascript
复制
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)
})

我使用以下方法调用这个测试文件:

代码语言:javascript
复制
# 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)

好像做了我想做的事,但是当看到结果时.

代码语言:javascript
复制
> 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只是返回的第一个测试。

它的工作原理:

  • 执行一个普通的测试。
  • 记者,目前正在使用,是获得(-- 1 --)
  • callr::r用于调用一个包含测试的测试块。
  • 在调用中,我尝试使用set_reporter,但with_reporter实际上是相同的。
  • callr::r调用返回记者(用get_reporter()尝试过,但with_reporter也返回记者(看不见))

现在返回的记者似乎很好,但是当使用set_reporter将其设置为实际的记者时,似乎并没有覆盖实际的记者。

注意,在-- 2 --中,reporter_out包含两个测试结果。

问题

我不太确定它会做什么,但最终我希望将结果添加到原始的记者(summary或) reporter_in )中,也就是说,如果不是某种副本)。

EN

回答 1

Stack Overflow用户

发布于 2021-12-30 16:28:36

我能想到的一个解决办法是将实际的测试执行移出callr::r调用之外,但将测试用例收集到其中。我认为这是很好的,只要您能够放置这些帮助函数(请参阅详细的示例) 在你的包裹里,您就可以编写测试,而且开销很小。

它不回答如何处理“记者”对象.

简单的例子:

代码语言:javascript
复制
test_outcome <- callr::r(
    function() {
        # devtools::load_all()
        list(
           check1 = mypackage::sum(5,5),  # some imaginary exported functions sum and name.
           check2 = mypackage::name()
        )
    }
)
test_that('My test case', {
    expect_equal(test_outcome$check1, 10)
    expect_equal(test_outcome$check2, 'Siete')
})

详尽的例子

请注意,从.add_test.exp_true都是函数定义,它们可以是最好包括在你的包裹里,因此在加载devtools::load_all()时它们是可用的。默认情况下,load_all还加载未导出的函数。

代码语言:javascript
复制
test_outcome <- callr::r(
    function() {
        # devtools::load_all()

        # Defining helper functions
        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)
        }

        # Performing the tests
        .exp_match('My name is Siete', 'My name is .*')
        .exp_equal(mypackage::sum(5,5), 10)  # some imaginary exported functions sum and name.
        .exp_match(mypackage::name(), 'Siete')
    
        .exp_false('package:testthat' %in% search())

        return(tst)
    },
    show = TRUE)

# Performing the actual testthat tests:
.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)

当将函数移到包中时,您还需要以下初始化函数。

代码语言:javascript
复制
tst <- new.env(parent = emptyenv())
tst$desc = ''
tst$tests = list()

.initialize_test <- function(desc) {
    tst$desc = desc
    tst$tests = list()
}

它的工作方式如下:

  • 创建了一个空列表:tst
  • 通过调用.exp_...函数,测试将添加到该列表中。
  • 包含测试的列表由callr::r中的函数返回
  • 然后我们遍历列表并执行每个测试。
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70529705

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档