【问题标题】:Testing private methods in R6 classes in R在 R 中测试 R6 类中的私有方法
【发布时间】:2016-05-12 14:28:52
【问题描述】:

我目前正在一个项目中使用 R6 类。

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

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

我怎样才能最好地做到这一点?

谢谢!

【问题讨论】:

  • 您是否应该测试您的私有方法,因为它们通常会从客户端代码中调用——间接(例如,从您的类的公共方法中),并且直接?将方法和数据成员设为私有的全部意义在于,它们不能从对象实例外部访问。
  • 谢谢@nrussell。对我来说,编写单元测试的目的是确保所有功能都按预期工作。为此,最好在尽可能低的级别编写单元测试。为执行更复杂操作的公共方法编写单元测试(例如,在各种设置中调用私有方法数百次)会使运行测试和调试失败变得更加复杂。

标签: r r6


【解决方案1】:

这是一个不需要环境修改或更改您要测试的类的解决方案,而是创建一个为您进行测试的新类。

R6 中,派生类可以访问private 其基类的方法(与C++Java 不同,您需要protected 关键字来获得相同的结果)。因此,您可以编写一个派生自您要测试的类的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

【讨论】:

    【解决方案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
    

    【讨论】:

      【解决方案3】:

      你可以在你的类中添加一个辅助方法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"
      

      【讨论】:

        猜你喜欢
        • 2019-01-23
        • 1970-01-01
        • 2018-01-07
        • 1970-01-01
        • 2019-02-01
        • 2020-11-08
        • 2019-08-04
        • 1970-01-01
        相关资源
        最近更新 更多