2016-05-12 64 views
1

我目前在项目中使用R6类。测试R6中R类中的私有方法R

我想写单元测试,也测试我正在使用的私有方法的功能(最好不要通过使用这些私有方法更复杂的公共方法)。

但是,我无法访问似乎访问私有方法。

我该如何做到最好?

谢谢!

+3

您是不是应该测试您的私有方法,因为它们通常会从客户端代码中间接调用 - 例如间接地(例如从您的类的公共方法中)调用,而不是*直接调用?使方法和数据成员保持私密的关键在于,它们不能从对象实例外部访问。 – nrussell

+1

谢谢@nrussell。对我而言,编写单元测试的目的是为了确保所有功能按预期工作。为此,单元测试最好写在尽可能最低的水平。为一个更复杂的公共方法编写单元测试(例如,在各种设置中调用私有方法数百次)使运行测试和调试失败变得更加复杂。 –

回答

4

这里不需要环境黑客或改变的解决方案你想要测试的类,而是创建一个新的类来为你做测试。

R6,派生类访问类中的方法private(不像C++Java在您需要的protected关键字archieve相同的结果)。因此,您可以编写一个从您要测试的类派生的TesterClass。例如:

library(R6) 

ClassToTest <- R6Class(
    private = list(
    privateMember = 7, 
    privateFunction = function(x){ 
     return(x * private$privateMember) 
    } 
) 
) 

TesterClass <- 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 

一个这种方法的优点是,它让你的环境清洁的情况下,要保存详细的测试结果。

2

目前有一种方法可以访问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 
1

您可以添加一个辅助方法get到类:

... 

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"