我们如何测试构建R包时未暴露的函数?

时间:2011-05-18 07:08:45

标签: unit-testing r tdd

我目前正在为R.开发graphical analysis package。我们正尝试使用Clean CodeTest-Driven Development(TDD)中的原则。但是,我们遇到了一个概念问题。

如何测试未曝光的功能?

考虑以下简化示例。 Outer()是我们在package中构建的功能,我们会将其列在NAMESPACE文件中,以便将其公开给用户。 Inner()是一个简短的(~5行)效用函数:

Outer <- function(...) {

  Inner <- function(...) {
    return(x)
  }

  return( Inner() )
}

我们package中的大多数用户公开函数都是简短的单行为Inner()样式函数的集合,这些函数位于用户可以调用的单个Outer()函数的保护伞下。 Granova.ds.ggplot()就是一个例子。 Clean Code强烈提倡这种模块化设计,我们对结果非常满意。但是我们不知道如何为它构建单元测试,因为我们想要测试的函数在Granova.ds.ggplot()函数的范围之外无法访问,因为我们设计了它。

我们遇到了几个想法/解决方案:

  1. 测试应该只能访问公共API。由于Inner()之类的功能在设计上并非公开(它们不会在NAMESPACE中导出),我们甚至不应该尝试测试它们。
  2. Hadley Wickham testthat package wiki表示支持使用R CMD check工作流程测试“非导出功能”。
  3. 如果所有其他方法都失败了,我们可能会以某种方式手动中断我们的Outer()函数以进行测试
  4. 到目前为止,这些解决方案都没有奏效

    解决方案1似乎是一个警察。我们相信,特别是在R中,拥有一个称为各种简短,单一责任的实用方法的顶级函数是明智的。不能测试这样的方法看起来很愚蠢,就像那种类型的东西有解决方案,但我们还没有找到。

    解决方案2可能有效,但到目前为止我们还没有开始工作。如果你尝试克隆our repository,那么采购inst/dev.R我相信你会在测试输出中找到它无法找到函数InitializeGgplot(),即使行中定义了said function granova.1w.ggplot()的613-615。同样,在终端上运行R CMD check似乎根本不执行任何测试。但是,它需要花费大量时间并向我们施加侮辱性错误: - (

    解决方案3在某种意义上是务实的,但与总是朝着项目目标状态的目标相反。这对我们没有意义。

    什么是理想的解决方案

    理想情况下,我们正在寻找一种方法来利用像testthat这样的软件包在我们编码时快速提供反馈,并允许我们测试中存在的<{1}}之类的函数/ em>像Inner()这样的函数。更好的方法是在不使用Outer()的情况下完成它,由于我们的某些功能的三维复杂性每次运行几乎需要一分钟。

    那么,我们缺少什么? TDD实践是否允许在R中测试外部/内部样式设置?如果他们这样做,我们怎样才能开发我们的包装?欢迎任何反馈,我会尽力回应任何不清楚的事情。

    谢谢!

2 个答案:

答案 0 :(得分:7)

如果Inner实现了您要测试的非平凡功能,我建议将Inner移至顶级,但不导出它。一般来说,我完全避免在其他函数中嵌套函数 - 它们很难测试。

你可以在开发过程中使用通常的测试功能进行测试,因为你可能只是在所有的R代码中采购而不用担心命名空间(至少我是如何开发的)。然后将R CMD checktest_package结合使用以确保测试在构建时仍然有效 - test_packages运行包名称空间中的测试,以便它们可以测试未导出的函数。

答案 1 :(得分:6)

IMO这里没有问题 - Inner只是Outer的一个不可拆卸的部分,所以测试外部测试内部。你愿意测试匿名功能吗?同样在这里。