跳过 R 中 M1mac 的测试

Posted

技术标签:

【中文标题】跳过 R 中 M1mac 的测试【英文标题】:Skip test on M1mac in R 【发布时间】:2021-12-23 01:43:03 【问题描述】:

根据 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 包的最佳编码实践(或长期解决方案),以解决特定测试在一个操作系统上失败的问题?

【问题讨论】:

【参考方案1】:

其他程序员是怎么做的

我不愿透露规范软件包,但有一些非常知名的软件包可以跳过某些操作系统进行特定测试:

https://github.com/chasemc/electricShine https://github.com/ropensci/arkdb

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

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

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

文档是怎么说的

This 是testthat 包的官方文章。它清楚地说明了您最好跳过测试的情况;然而,这些陈述往往更具推荐性而非强制性:

您正在测试一个偶尔会失败的 Web 服务,并且您不想在 CRAN 上运行测试。或者,API 可能需要身份验证,而您只能在安全地分发了一些机密后才能运行测试。

您依赖于并非所有操作系统都具备的功能,并希望确保您的代码不会在无法运行的平台上运行。这个平台往往是 Windows,因为除其他外,它缺乏完整的 utf8 支持。

您正在为多个版本的 R 或多个版本的依赖项编写测试,并且您想在某个功能不可用时跳过。如果未安装建议的软件包,您通常不需要跳过测试。 这仅在特殊情况下才需要,例如当某个软件包在某些操作系统上不可用时

我已经强调了所有关于操作系统的内容。根据您的问题,我可以得出结论,您的情况属于“您依赖并非所有操作系统都具有的功能”的陈述,因为您很可能遇到了 M1 Mac 操作系统中的错误 s> 自macOS build has a slightly different way of calculating extended-precision floating-point numbers[1]:

“本机”构建速度稍快一些(对于某些任务而言,速度相当快),但由于 ARM 硬件缺乏扩展精度,因此可能会给出与更常见的“x86_64”平台(在 macOS 和其他操作系统上)不同的数值结果浮点运算。

意识形态坚持什么

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

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

单元测试通常是由软件开发人员编写和运行的自动化测试,以确保应用程序的一部分(称为“单元”)符合其设计并按预期运行。

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

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

如果不是,则意味着您的代码包含要在投入生产之前修复的错误。在这种情况下,一旦你修复它,测试应该会在你有问题的操作系统上成功。

我的代码在 M1mac 上以数字方式失败,但在其他平台上没有,同时在返回非常小的值的函数上使用 stats::integrate。

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

根据您的说法,很难理解是哪种情况,但我相信,如果您的套餐对 99.99% 的观众来说是可行的,那么请继续跳过这个烦人的测试,以获取剩下的 0.01 个百分位数的可能性环境。也许您应该在 README.MD 中的某处注明您的软件包存在此问题。

这样其他开发人员会意识到这一点,而那些使用 M1Mac OS 的开发人员很可能会找到解决方法或自行修复它 - 以防您正在创建一个开源项目。


注意事项:

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

【讨论】:

“因为您很可能在 M1 Mac 操作系统中遇到过错误”我不同意。 "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."【参考方案2】:

作为包开发人员(但绝不是 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 Mac 上不准确,并描述您为解决基本数字问题所做的任何尝试(或为什么无法解决)。

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

至于你的数字问题:

尝试找到一种更稳定的算法来计算被积函数。例如,将prod(x) 替换为exp(sum(log(x))) 可能会有所帮助。

integrate的可选参数进行实验,即rel.tolabs.tol

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

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

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

【讨论】:

以上是关于跳过 R 中 M1mac 的测试的主要内容,如果未能解决你的问题,请参考以下文章

如何在 M1 Mac 上运行 querydsl 项目测试?

跳过测试文件 Jest 中的一项测试

在 Maven 中跳过某些模块中的测试

如何跳过 Codeception cest 测试

告诉 Eclipse 跳过测试

如何强制 PHPUnit 在跳过的测试中失败?