如何测试 "warnings()" 产生的特定警告?
How to test for specific warning(s), as produced by "warnings()"?
问题
我正在使用 read_delim
函数读取大量 csv 文件(非逗号分隔)。这会产生警告,因为某些列具有相同的名称。我不想编辑原始文件,并且在使用 read_delim
读入它们时无法更改列名。所以这些警告是不可避免的。但是我想做一个测试,这些是唯一生成的警告,并且没有其他警告,例如错误的列规范等。
我自己能想到的
我可以在 运行 代码后使用 myWarnings <- warnings()
捕获警告,但我不确定如何用它测试任何东西。问题是 myWarnings
是 class warnings
的列表,我不确定如何测试。例如 myWarnings[[1]]
产生 NULL
,所以我无法测试每个元素的元素。它也不是字符向量而是列表。
通常的做法是在函数 运行ning 时捕获警告。例如 testthat::expect_warning(read_delim(...))
,但为了做到这一点,我必须 运行 我的代码两次:一次用于结果,一次用于测试。我不想这样做,因为它需要太多时间(而且这不是一种非常干净的做事方式)。
代码
# Pseudocode because you don't have my input files anyway
library(tidyverse)
myInputs <- list.files("myFolder", pattern = ".csv$")
myColTypes <- cols(col1 = col_character(), col2 = col_logical(), etc.)
myData <- map(myInputs, read_delim, delim = "|", col_types = myColTypes)
之后R在控制台告诉我:There were 36 warnings (use warnings() to see them)
。这些警告中的每一个都是:Duplicated column names deduplicated: 'col' => 'col_1' [32], 'col' => 'col_2' [54], 'col' => 'col_3' [211]
.
我希望能够做这样的事情:
# Again pseudocode, because this is what I would like but it doesn't work.
myWarnings <- warnings()
testthat::expect_equal(
myWarnings,
warning("Duplicated column names deduplicated: 'col' => 'col_1' [32], 'col' => 'col_2' [54], 'col' => 'col_3' [211]"
)
您可以使用 testthat::expect_named()
。为什么?您从 warnings()
获得的列表是一个命名列表,其中的名称是警告消息。让我们看一个例子:
for ( i in 1:10 ) {
x <- log(-i)
}
# Warning messages:
# 1: In log(-i) : NaNs produced
# ...
# 10: In log(-i) : NaNs produced
w <- warnings()
str(w)
# List of 10
# $ NaNs produced: language log(-i)
# ...
# $ NaNs produced: language log(-i)
# - attr(*, "dots")= list()
# - attr(*, "class")= chr "warnings"
names(w)
# [1] "NaNs produced" "NaNs produced" "NaNs produced" "NaNs produced"
# [5] "NaNs produced" "NaNs produced" "NaNs produced" "NaNs produced"
# [9] "NaNs produced" "NaNs produced"
然后我们可以使用testthat::expect_named()
来测试警告消息的相等性:
testthat::expect_named(w, rep("NaNs produced", 10))
问题
我正在使用 read_delim
函数读取大量 csv 文件(非逗号分隔)。这会产生警告,因为某些列具有相同的名称。我不想编辑原始文件,并且在使用 read_delim
读入它们时无法更改列名。所以这些警告是不可避免的。但是我想做一个测试,这些是唯一生成的警告,并且没有其他警告,例如错误的列规范等。
我自己能想到的
我可以在 运行 代码后使用 myWarnings <- warnings()
捕获警告,但我不确定如何用它测试任何东西。问题是 myWarnings
是 class warnings
的列表,我不确定如何测试。例如 myWarnings[[1]]
产生 NULL
,所以我无法测试每个元素的元素。它也不是字符向量而是列表。
通常的做法是在函数 运行ning 时捕获警告。例如 testthat::expect_warning(read_delim(...))
,但为了做到这一点,我必须 运行 我的代码两次:一次用于结果,一次用于测试。我不想这样做,因为它需要太多时间(而且这不是一种非常干净的做事方式)。
代码
# Pseudocode because you don't have my input files anyway
library(tidyverse)
myInputs <- list.files("myFolder", pattern = ".csv$")
myColTypes <- cols(col1 = col_character(), col2 = col_logical(), etc.)
myData <- map(myInputs, read_delim, delim = "|", col_types = myColTypes)
之后R在控制台告诉我:There were 36 warnings (use warnings() to see them)
。这些警告中的每一个都是:Duplicated column names deduplicated: 'col' => 'col_1' [32], 'col' => 'col_2' [54], 'col' => 'col_3' [211]
.
我希望能够做这样的事情:
# Again pseudocode, because this is what I would like but it doesn't work.
myWarnings <- warnings()
testthat::expect_equal(
myWarnings,
warning("Duplicated column names deduplicated: 'col' => 'col_1' [32], 'col' => 'col_2' [54], 'col' => 'col_3' [211]"
)
您可以使用 testthat::expect_named()
。为什么?您从 warnings()
获得的列表是一个命名列表,其中的名称是警告消息。让我们看一个例子:
for ( i in 1:10 ) {
x <- log(-i)
}
# Warning messages:
# 1: In log(-i) : NaNs produced
# ...
# 10: In log(-i) : NaNs produced
w <- warnings()
str(w)
# List of 10
# $ NaNs produced: language log(-i)
# ...
# $ NaNs produced: language log(-i)
# - attr(*, "dots")= list()
# - attr(*, "class")= chr "warnings"
names(w)
# [1] "NaNs produced" "NaNs produced" "NaNs produced" "NaNs produced"
# [5] "NaNs produced" "NaNs produced" "NaNs produced" "NaNs produced"
# [9] "NaNs produced" "NaNs produced"
然后我们可以使用testthat::expect_named()
来测试警告消息的相等性:
testthat::expect_named(w, rep("NaNs produced", 10))