Соберите непроверенные/непроверенные предупреждения, которые были выпущены во время тестирования, что::test_dir в R

#r #warnings #testthat

#r #предупреждения #проверьте это

Вопрос:

Я хочу запустить все тесты и получить результаты тестирования и выданные предупреждения, чтобы программно создать отчет об уценке, показывающий результаты тестирования и потенциальные предупреждения, возникшие в тестируемом коде.

Но, похоже, нет никакого способа получить или зафиксировать предупреждения во время тестового запуска! Я понимаю, что тесты выполняются в закрытой среде, но действительно ли нет способа разрешить тесту выдавать мне предупреждения?

В следующей настройке warn_list переменная всегда пуста.

Три файла для минимального примера:

./tests/testthat.R

 library(testthat)   warn_list lt;- list() outcome lt;- withCallingHandlers(   testthat::test_dir(testthat::test_path()),    warning = function(w) {  warn_list lt;lt;- c(warn_list, list(msg = w$message))  } )  rmarkdown::render(input = './tests/create_test_report.Rmd')  

Обратите внимание, что outcome переменная (и warn_list ) используется в файле Rmd.

./tests/testthat/test_thrown_warn.R

 test_that("Throws Warning", {   testthat::expect_equal(  {  warning('Example warning fired inside test!') # WHERE WARN IS THROWN  5  }, 5)   })  

./tests/create_test_report.Rmd

 --- title: "test_results_overview" output: md_document ---  ## Produced warnings during the tests:   ```{r warnings_during_testing, echo=FALSE} knitr::kable(warn_list) # WHERE I TRY TO SHOW IT ```  

Комментарии:

1. Я подозреваю testthat , что улавливаю предупреждения. Возможно, установка reporter аргумента на что-то не по умолчанию (или настроенное) даст вам то, что вы хотите.

2. Хорошее замечание, я читал о разных (совершенно недокументированных) репортерах, но не экспериментировал с ними. Если я правильно помню, объект класса testthat_results, возвращаемый тестами, остается прежним, хотя…? Посмотрю

3. Если вы сомневаетесь в выборе между ответами: Выберите «user2554330» его ответ, если вам нужно только само предупреждение (или пропуски или сбои). Выберите мой ответ, если вам нравится строка, в которой это произошло, и еще какой-то контекст, например файл/тест/контекст и т. Д.

4. На самом деле, awarning объект, упомянутый в моем ответе, — это больше, чем просто объект условия. awarning$test даст название теста, и местоположение можно будет найти из awarning$srcref компонента.

Ответ №1:

Похоже SummaryReporter , объект reporter записывает предупреждения. Как вы упомянули в своем комментарии, они очень минимально документированы, но, похоже, это делает это:

 library(testthat) summary lt;- SummaryReporter$new() test_file("somewarnings.R", reporter = summary) summary$warnings$as_list()  

Каждое из предупреждений приводит к записи в списке из последнего оператора. Они хранятся как объекты условий, поэтому вы можете делать такие вещи, как

 awarning lt;- summary$warnings$as_list()[[1]] getSrcFilename(awarning$srcref)  

Комментарии:

1. Это потрясающе! Я придумал какой-то альтернативный способ, который я также опубликую, но ваш, я думаю, намного лучше, поэтому приму его как ответ.

Ответ №2:

Альтернативное решение фактически доступно внутри testthat_results объекта. Он включает в себя конкретные ответы на тестовые случаи, такие как предупреждения, пропущенные тесты или ошибки аварийных тестов, но содержание не очень хорошо структурировано.

Например, в тестовом наборе, показанном в примере, будут показаны три поля результатов, в то время как есть только два оператора » ожидай_…». Средний будет иметь класс c('expectation_warning', 'expectation', 'condition') и содержать объект предупреждения.

Альтернативным решением является получение этих предупреждений (и, возможно, ошибок и пропусков в качестве бонуса) из результатов, подобных этому:

 outcome lt;- testthat::test_dir(testthat::test_path(), stop_on_failure = FALSE)  create_warn_df lt;- function(res) {  data.frame(test = res$test, warning_msg = res$message) }   warn_df lt;- data.frame() for (i_test in seq_along(outcome)) {  tst lt;- outcome[[i_test]]    for (i_res in seq_along(tst$results)) {  res lt;- tst$results[[i_res]]    if (is(res, "expectation_warning")) {  warn_df lt;- rbind(warn_df, create_warn_df(res))  }   } }   knitr::kable(warn_df)  

Примечание: «create_warning_str» отформатирует таблицу и может получить гораздо больше информации, например, стек и т. Д. Из объекта предупреждения.

Результаты теста находятся в outcome[[X]]$results[[Y]] папке, где X находится обрабатываемый файл и Y является тестовым случаем (или предупреждением, как описано ранее). Количество Y элементов не равно количеству тестовых случаев.

Более продвинутый пример:

Это включает в себя номер строки, в которой это произошло, и, кроме того, включает ошибки и пропуски. Он также показывает «файл» вместо «тест» (имя).

 create_warn_df lt;- function(file, src_ref, warn_msg) {  data.frame('file' = file, 'line' = getSrcLocation(src_ref), 'warning_msg' = warn_msg) }   warn_df lt;- data.frame() for (i_test in seq_along(outcome)) {  tst lt;- outcome[[i_test]]    for (i_res in seq_along(tst$results)) {  res lt;- tst$results[[i_res]]    if (is(res, "expectation_warning")) {  warn_df lt;- rbind(warn_df, create_warn_df(tst$file, res$srcref, res$message))  } else if (is(res, "expectation_error")) {  warn_df lt;- rbind(warn_df, create_warn_df(tst$file, res$srcref, paste('An error crashed this test:', res$message)))  } else if (is(res, "expectation_skip")) {  warn_df lt;- rbind(warn_df, create_warn_df(tst$file, res$srcref, paste('A test is skipped,', res$message)))  }  } }   knitr::kable(warn_df)