在 R 中跳过对 M1mac 的测试

Skip test on M1mac in R

根据 Carl Boettiger 在 this thread 中的说法,“...当测试失败时。与 Solaris 一样,当平台上安装了上游依赖项但实际上并未安装时,其中一些失败可能会发生 运行 ”我的代码在 M1mac 上在数字上失败,但在其他平台上却没有,同时在返回非常小的值的函数上使用 stats::integrate

我应该跳过 M1mac (arm64) 上的测试吗?

require(testthat)
test_that("correct numeric solution", {
     skip_on_os("mac", arch = "aarch64")

     # code of the test using expect_equal()
})

或者,调整 expect_equal() 中的 tolerance 参数是否可以帮助解决一个系统上的特定问题?如果是,如果我的结果是 1e-9(现在使用 tolerance = 1e-6,并且测试失败),tolerance 应该更改为什么值?

更笼统地说,什么是最佳编码实践(或长期解决方案) CRAN 上的 R 包解决特定测试失败的问题 OS?

其他程序员是怎么做的

我犹豫要不要谈论规范包,但有一些相当知名的包会跳过某些操作系统进行特定测试:

上面存储库中的几个示例:

  1. Example 1. 跳过 Solaris 平台上的核心功能测试。

  2. Example 2. 跳过 Linux 的安装测试(此项目中的其他测试似乎涵盖所有操作系统)。

文档的内容

Thistestthat包的官方文章。它清楚地说明了在什么情况下你最好跳过测试;然而,这些陈述往往更具建议性而非命令性:

You’re testing a web service that occasionally fails, and you don’t want to run the tests on CRAN. Or maybe the API requires authentication, and you can only run the tests when you’ve securely distributed some secrets.

You’re relying on features that not all operating systems possess, and want to make sure your code doesn’t run on a platform where it doesn’t work. This platform tends to be Windows, since amongst other things, it lacks full utf8 support.

You’re writing your tests for multiple versions of R or multiple versions of a dependency and you want to skip when a feature isn’t available. You generally don’t need to skip tests if a suggested package is not installed. This is only needed in exceptional circumstances, e.g. when a package is not available on some operating system.

我已经突出显示了所有关于操作系统的文章。根据你的问题,我可以得出结论,你的情况属于“你依赖的功能并非所有操作系统都拥有”的陈述,因为你很可能在 M1 [=84] 中遇到了错误=] 操作系统macOS build has a slightly different way of calculating extended-precision floating-point numbers[1]:

The ‘native’ build is a little faster (and for some tasks, considerably so) but may give different numerical results from the far more common ‘x86_64’ platforms (on macOS and other OSes) as ARM hardware lacks extended-precision floating-point operations.

意识形态坚持什么

值得我们花时间回顾一下为什么首先要发明单元测试。

尽管所有关于维基百科不可靠的讨论,我相信这个来源被我的绝大多数同事认为是“规范的”,which states:

Unit tests are typically automated tests written and run by software developers to ensure that a section of an application (known as the "unit") meets its design and behaves as intended.

为了从意识形态的角度回答你的问题,我们只需要回答一个问题:你的代码目前是否按预期工作?

如果您认为您的功能对最终用户来说足够全面,即使它在特定 OS 上部分无法正常工作,请随时跳过测试。

如果不是,则意味着您的代码包含需要在投入生产之前修复的错误。在这种情况下,一旦您修复它,测试应该会成功并出现问题 OS.

My code fails numerically on M1mac, but not on other platforms, while using stats::integrate on functions returning very small values.

我自己的(可能有偏见的)意见

根据你的话,很难理解是哪一个,但我相信如果你的包对 99.99% 的观众来说是可行的,请继续跳过这个烦人的测试,剩下的 0.01 个百分位数可能的环境。也许您应该在 README.MD 的某个地方注意到您的包裹有这个问题。

这样其他开发人员就会知道它,而那些使用 M1Mac OS 的开发人员很可能会找到解决方法或自己修复它 - 如果您正在创建一个开放 -源项目。


备注:

[1]。感谢 的评论,我更新了我的答案。

作为包开发人员(但无论如何都不是 CRAN 专家),我的建议是重新制定( 跳过)测试。您可以将测试作为记录问题的机会。以下是我将采取的步骤:

  • 定义特定于平台的断言。在 M1 Mac 上,通过将失败的 expect_equal 调用包装在 expect_error 中,断言近似值不等于您用于其他平台的容差下的积分的精确值.然后断言这两个 在一些最小的、更大的公差和更不严格的 expect_equal 调用下相等。您的测试块将包含如下内容:

    x <- approximate_integral_value
    y <- exact_integral_value
    
    ## If testing on M1 Mac
    if (tolower(Sys.info()[["sysname"]]) == "darwin" && R.version[["arch"]] == "aarch64") {
      ## Expect strict test to fail
      expect_error(expect_equal(x, y, tolerance = 1e-9)) 
      ## Expect less strict test to pass
      expect_equal(x, y, tolerance = 1e-4)
    ## Otherwise
    } else {
      ## Expect strict test to pass
      expect_equal(x, y, tolerance = 1e-9)
    }
    

    这样,您将检测问题是否自行解决(第一个 expect_equal 将通过,导致 expect_error 失败)并且您将检测问题是否变得更糟(第二个 expect_equal 将失败)。在这两种情况下,您都需要更新测试代码。

  • expect_error 调用附近发表评论,解释为什么 M1 Macs 上的积分近似不准确,并描述您为解决基础数值问题所做的任何尝试问题(或无法解决的原因)。

  • 如果您认为您的程序包中的函数可能无法在 M1 Macs 上运行,因为此测试失败,请在其中使用 warningstop那些功能让用户知道。如果这些功能是您的软件包功能的核心,请在更显眼的地方添加平台说明(例如,在您的软件包网站的登录页面上)。

关于你的数值问题:

  • 尝试寻找更稳定的算法来计算被积函数。例如,将 prod(x) 替换为 exp(sum(log(x))).

    可能会有所帮助
  • 试验 integrate 的可选参数,即 rel.tolabs.tol.

FWIW,有专门针对此类问题的论坛,即 R-package-devel and R-SIG-Mac 邮件列表:

  • R-package-devel 适用于“处理这个包开发问题的最佳实践是什么?”这个问题。在那里,您更有可能直接从 CRAN 维护者那里得到答案。

  • R-SIG-Mac 适合这个问题,“为什么我只在 M1 Mac 上遇到这种行为?”在那里,您更有可能从为 Macs 开发 R 的 R 核心团队成员那里得到答案。 [编辑:@Roland 在评论中指出,为基于 ARM 的平台构建的原生 R 不支持扩展精度算法。]