问题描述
我在 R 中使用 testthat 包进行单元测试。我有一个函数 CalcByResultSubModel,它还有一个函数 CalculateX,它在主函数中被调用。这是主要功能,
CalcByResultSubModel = function(doll_data,fn_master,modelPath) {
# load sub model result
load(modelPath)
# calculation
for(abc in c("ABC",fn_master$fn_a)) {
# columns
col_name = paste0("x",abc)
iterModel = resultSubmodel[[abc]]
# calculate yhat X
doll_data[,col_name] = iterModel %>%
purrr::map(.,function(imodel) {
CalculateX(data,imodel)
}) %>%
as.data.frame(.) %>%
apply(.,1,mean)
message(paste(col_name,"calculated"))
}
CalculateX = function(data,model) {
iterData = data %>%
dplyr::select(model$feature_names) %>%
as.matrix(.)
set.seed(131)
result = predict(model,iterData,missing = NA)
result = matrix(result,2)[2,]
return(result)
}
为了执行单元测试,我们必须模拟函数 CalculateX。但这里的复杂之处在于,该函数是在主函数的 for 循环中调用的。在我的单元测试中,我对这个场景很陌生。任何人都可以帮助我模拟 for 循环中的函数吗?这是模拟的代码,我试过了。
local_mock(CalculateX = function(data,model){
for (abc in c("ABC",fn_master$fn_a)
case_when(
abc == "feature1" ~ .ReadCsvWrapper("feature1.csv"),abc == "feature2" ~ .ReadCsvWrapper( "feature2.csv"),abc == "feature3" ~ .ReadCsvWrapper("feature3.csv"))
})
But the above approach doesn't seem to work for me. Can anyone help me with this?
解决方法
您的代码中有几个问题。首先,CalcByResultSubModel
在循环中调用 CalculateX
for(abc in c("ABC",fn_master$fn_a)) {
# columns
col_name = paste0("x",abc)
iterModel = resultSubmodel[[abc]]
# calculate yhat X
doll_data[,col_name] = iterModel %>%
purrr::map(.,function(imodel) {
CalculateX(data,imodel)
}) %>%
as.data.frame(.) %>%
apply(.,1,mean)
message(paste(col_name,"calculated"))
}
所以你不需要把 for(abc in c("ABC",fn_master$fn_a))
放入模拟函数中。只需将其设置为返回与调用实际函数类似的结果即可。
第二个问题是,在真正的 CalculateX
中,您有 set.seed(131)
。这几乎肯定是一个坏主意。每次调用 CalculateX
时,它都会将随机数生成器重置为固定设置,这使其完全非随机,并且之后还会调用随机数函数重复其输出。
在测试脚本的顶部设置一次种子通常是一个好主意,这样测试是可预测的,但像您一样经常重置它不是。