在 R 中的 R6 类 中测试私有方法
Testing private methods in R6 classes in R
我目前正在项目中使用 R6 类。
我想编写单元测试来测试我正在使用的私有方法的功能(最好不要通过使用这些私有方法的更复杂的 public 方法)。
但是,我似乎无法访问私有方法。
我该怎么做最好?
谢谢!
目前有一种方法可以访问 R6 对象的私有环境。然而,由于这是以一种未记录的方式进入一个对象,它可能会在未来崩溃......不过我认为这不会很快发生。
# Gets private environment from an R6 object
get_private <- function(x) {
x[['.__enclos_env__']]$private
}
A <- R6::R6Class("A",
private = list(x = 1)
)
a <- A$new()
get_private(a)$x
# [1] 1
您可以将辅助方法 get
添加到您的 class:
...
A <- R6::R6Class(
"A",
private = list(
private_print = function(){print("Ola")}
),
public = list(
get = function(name=NULL){
# recursion
if( length(name)>1 ){
tmp <- lapply(name, self$get)
names(tmp) <- name
return(tmp)
}
if(is.null(name)){
self$message("no input, returning NULL")
return(NULL)
}
# self
if(name=="self"){
return(self)
}
# in self
if( name %in% names(self) ){
return(base::get(name, envir=self))
}
# private or in private
if( exists("private") ){
if(name=="private"){
return(private)
}else if(name %in% names(private) ){
return(base::get(name, envir=private))
}
}
# else
self$message("name not found")
return(NULL)
}
)
)
...
比这样使用它:
a <- A$new()
a$get("private_print")()
## [1] "Ola"
这是一个不需要环境黑客攻击或改变您想要测试的 class 的解决方案,而是创建一个新的 class 来为您进行测试。
在 R6
中,派生 classes 可以访问其基础 classes 的 private
方法(不同于 C++
或 Java
你需要 protected
关键字来获得相同的结果)。因此,您可以编写一个从要测试的 class 派生的 TesterClass
。例如:
ClassToTest <- R6::R6Class(
private = list(
privateMember = 7,
privateFunction = function(x) {
return(x * private$privateMember)
}
)
)
TesterClass <- R6::R6Class(
inherit = ClassToTest,
public = list(
runTest = function(x = 5) {
if (x * private$privateMember != private$privateFunction(x))
cat("Oops. Somethig is wrong\n")
else
cat("Everything is fine\n")
}
)
)
t <- TesterClass$new()
t$runTest()
#> Everything is fine
此方法的一个优点是您可以将详细的测试结果保存在 TesterClass
。
我目前正在项目中使用 R6 类。
我想编写单元测试来测试我正在使用的私有方法的功能(最好不要通过使用这些私有方法的更复杂的 public 方法)。
但是,我似乎无法访问私有方法。
我该怎么做最好?
谢谢!
目前有一种方法可以访问 R6 对象的私有环境。然而,由于这是以一种未记录的方式进入一个对象,它可能会在未来崩溃......不过我认为这不会很快发生。
# Gets private environment from an R6 object
get_private <- function(x) {
x[['.__enclos_env__']]$private
}
A <- R6::R6Class("A",
private = list(x = 1)
)
a <- A$new()
get_private(a)$x
# [1] 1
您可以将辅助方法 get
添加到您的 class:
...
A <- R6::R6Class(
"A",
private = list(
private_print = function(){print("Ola")}
),
public = list(
get = function(name=NULL){
# recursion
if( length(name)>1 ){
tmp <- lapply(name, self$get)
names(tmp) <- name
return(tmp)
}
if(is.null(name)){
self$message("no input, returning NULL")
return(NULL)
}
# self
if(name=="self"){
return(self)
}
# in self
if( name %in% names(self) ){
return(base::get(name, envir=self))
}
# private or in private
if( exists("private") ){
if(name=="private"){
return(private)
}else if(name %in% names(private) ){
return(base::get(name, envir=private))
}
}
# else
self$message("name not found")
return(NULL)
}
)
)
...
比这样使用它:
a <- A$new()
a$get("private_print")()
## [1] "Ola"
这是一个不需要环境黑客攻击或改变您想要测试的 class 的解决方案,而是创建一个新的 class 来为您进行测试。
在 R6
中,派生 classes 可以访问其基础 classes 的 private
方法(不同于 C++
或 Java
你需要 protected
关键字来获得相同的结果)。因此,您可以编写一个从要测试的 class 派生的 TesterClass
。例如:
ClassToTest <- R6::R6Class(
private = list(
privateMember = 7,
privateFunction = function(x) {
return(x * private$privateMember)
}
)
)
TesterClass <- R6::R6Class(
inherit = ClassToTest,
public = list(
runTest = function(x = 5) {
if (x * private$privateMember != private$privateFunction(x))
cat("Oops. Somethig is wrong\n")
else
cat("Everything is fine\n")
}
)
)
t <- TesterClass$new()
t$runTest()
#> Everything is fine
此方法的一个优点是您可以将详细的测试结果保存在 TesterClass
。