I am currently using R6 classes in a project.
I would like to write unit tests that also test the functionality of private methods that I am using (preferably by not going through the more complicated public methods that are using these private methods).
However, I can't access seem to access the private methods.
How do I best do that?
Thanks!
Here is a solution that does not require environment hacking or altering the class you want to test, but instead creating a new class that does the testing for you.
In R6
, derived classes have access to private
Methods of their base classes (unlike in C++
or Java
where you need the protected
keyword to archieve the same result). Therefore, you can write a TesterClass
that derives from the class you want to test. For example:
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
One advantage of this approach is that you can save detailed test results in the TesterClass
.
There is currently a way to access the private environment of an R6 object. However, since this is reaching into an object in an undocumented way, it may break in the future... I don't think that will happen any time soon though.
# 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
you can add a helper method get
to your 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)
}
)
)
...
Than use it like this:
a <- A$new()
a$get("private_print")()
## [1] "Ola"
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.