R попробуй поймать с проверкой это ожидание

У меня есть следующая функция:

fun = function(expr) {
  mc = match.call()

  env = as.environment(within(
    list(),
    expr = eval(mc$expr)
  ))

  return(env)
}

который вызывается внутри tryCatch(), так что любые ошибки в expr обрабатываются корректно.

Он отлично работает со стандартным условием ошибки:

tryCatch({
  fun({
    stop('error')
  })
}, error = function(e) {
  message('error happened')
})

# error happened

Однако он не фиксирует testthat ошибок ожидания (что предпочтительнее для моего конкретного варианта использования):

library(testthat)

tryCatch({
  fun({
    expect_true(FALSE)
  })
}, error = function(e) {
  message('expectation not met')
})

# Error: FALSE isn't true.

или проще:

library(testthat)

tryCatch({
  expect_true(FALSE)
}, error = function(e) {
  message('expectation not met')
})

# Error: FALSE isn't true.

Ошибка ожидания не обнаружена.

Эта проблема появилась после обновления с R 3.2.2 до R 3.3.0, т.е. ошибки ожидания были обнаружены только в R 3.2.2.

Есть ли способ сделать testthat ожидания пойманными tryCatch() в R 3.3.0?


person oddHypothesis    schedule 16.06.2016    source источник
comment
Функции expect_xxx вызывают expect, который, в свою очередь, вызывает withRestarts. Я не знаю точно, что это делает, но, похоже, это корень проблемы, с которой вы столкнулись.   -  person Dason    schedule 17.06.2016
comment
@Dason Да, я это заметил. Я не уверен, что так было всегда (например, когда я впервые разработал свой код с R 3.2.2). В идеале я бы предпочел обойти его текущее поведение без исправления обезьяны.   -  person oddHypothesis    schedule 17.06.2016


Ответы (1)


Я установил отладчик на expect(), затем прошел пару строк кода (вывод отредактирован для краткости) и посмотрел на класс сигнализируемого условия.

> debug(expect)
> xx = expect_true(FALSE)
...
Browse[2]> n
debug: exp <- as.expectation(exp, ..., srcref = srcref)
Browse[2]>
...
Browse[2]> class(exp)
[1] "expectation_failure" "expectation"         "condition"   
Browse[2]> Q
> undebug(expect)       

так что это не условие класса "ошибка" и может быть явно поймано

> tryCatch(expect_true(FALSE), expectation_failure=conditionMessage)
[1] "FALSE isn't true.\n"

Вы также можете поймать класс expectation.

Перезапуск позволяет продолжить, если это было как-то важно.

result <- withCallingHandlers({
    expect_true(FALSE)
    expect_true(!TRUE)
    expect_true("this sentence")
}, expectation_failure=function(e) {
    cat(conditionMessage(e))
    invokeRestart("continue_test")
})

с выходом

FALSE isn't true.
!TRUE isn't true.
"this sentence" isn't true.
> result
[1] FALSE

Можно также поймать или обработать успехи

> tryCatch(expect_true(TRUE), expectation_success=class)
[1] "expectation_success" "expectation"         "condition"  
person Martin Morgan    schedule 17.06.2016
comment
Спасибо! Из документации tryCatch() мне, конечно, не было ясно, что можно указать обработчики для определенных классов. Еще один, чтобы добавить к моему списку приемов R. - person oddHypothesis; 18.06.2016