testing - 是否可以在 Julia 中组织健全性检查,以便在加载包时轻松编译它们?

标签 testing julia assert flags code-organization

我正在开发一个需要快速运行且正确的包。我只想编写一个函数,但有两个该函数的“版本”:一个在检测到任何类型的有趣业务时立即停止,另一个则尽可能快地运行。我的想法是在随机输入样本上运行函数的严格版本,如果没有失败,则在整个输入集上运行快速版本。我绝对没有计算能力来对每个输入进行每次检查,尽管如果可以的话我会睡得更轻松。 (我认为这已经是解决验证问题的错误方法,所以如果您有更好的组织方法,请随意提出建议,而不是对下面的具体改进。)

到目前为止,我已经破解了这个问题的临时解决方案如下:

module Foo

export some_function

const using_removeable_assertions = true

macro RemoveablyAssert(the_condition)
    if using_removeable_assertions
        return esc(:($the_condition || error("Assertion failed.")))
    else
        return esc("")
    end
end

function some_function(x::Float64,y::Float64)
    #Say this should only be called on positive numbers
    @RemoveablyAssert x>0
    @RemoveablyAssert y>0
    (x + y/2.0)::Float64
end

end

using Foo

所以这有效,

julia> some_function(1.0,1.0)
1.5

julia> some_function(1.0,-1.0)
ERROR: Assertion failed.
 in some_function at none:18

如果我重新加载手动更改了 const using_removeable_assertions = false 的模块,那么它不仅会跳过这些检查,

julia> some_function(1.0,1.0)
1.5

julia> some_function(1.0,-1.0)
0.5

但实际上,正如预期的那样, native 代码与我从未放置过这些行的相同函数相同:

julia> @code_native some_function(1.0,1.0)
    .section    __TEXT,__text,regular,pure_instructions
Filename: none
Source line: 19
    pushq   %rbp
    movq    %rsp, %rbp
    movabsq $13174486592, %rax      ## imm = 0x31142B640
Source line: 19
    vmulsd  (%rax), %xmm1, %xmm1
    vaddsd  %xmm0, %xmm1, %xmm0
    popq    %rbp
    ret

例如如果我定义

function some_function_2(x::Float64,y::Float64)
    (x + y/2.0)::Float64
end

然后

julia> @code_native some_function_2(1.0,1.0)
    .section    __TEXT,__text,regular,pure_instructions
Filename: none
Source line: 2
    pushq   %rbp
    movq    %rsp, %rbp
    movabsq $13174493536, %rax      ## imm = 0x31142D160
Source line: 2
    vmulsd  (%rax), %xmm1, %xmm1
    vaddsd  %xmm0, %xmm1, %xmm0
    popq    %rbp
    ret

因此:这是解决方案所需的两个属性,

  1. 打开/关闭大量严格的健全性检查应该像拨动开关一样简单
  2. 在“关闭”的情况下, native 代码应该完全清除对检查的任何引用;特别是,不应该有 关闭情况下的性能差异

但我想要一个更少手动、更惯用或更标准的解决方案。

请注意,手动为每个函数定义两个版本是不切实际的,因为维护它们会很麻烦。所以我考虑过使用另一个为每个 some_function 生成 some_function_safe 的宏,然后以这种方式手动运行安全检查,但我希望有更好的解决方案,类似于 julia 的命令行参数,但特定于模块。例如。 使用 [safemode=yes] Foo

相关地,我想知道是否有一种好的方法来处理多个检查“级别”,而不是一些类似的 hack,例如定义全局“安全级别”,然后在全局安全级别超过特定检查级别的情况下使用宏有条件地注入(inject)检查。如果上面的 [safemode=yes] 想法可以实现,那么这当然也可以实现,但我想知道是否有更好的方法来组织这些类型的检查。

(FWIW,我认为这些检查是对一个大型测试套件的补充,而不是替代。单独的测试套件并不能让我睡个好觉。此外,虽然我的示例是参数验证,但我想使用这些检查不仅用于前置条件和后置条件,还用于各种健全性检查,例如检查方法主体中的不变量以及针对我已经犯下并修复的错误编写特定检查等)

最佳答案

我为我的 Julia 工作做了一些非常相似的事情,我有一个宏可以完全删除,或者如果编译进去,检查一个我可以设置的掩码来控制实际检查哪些。 就单元测试而言,我们一直在使用 FactCheck.jl 包。 我们计划设置代码来进行代码覆盖测试(我们不能将我们的内部代码放在 GitHub 上,在那里设置起来很简单),我认为这与单元测试一起至关重要,以确保相当好的代码. 如果您的代码在 GitHub 上,我认为从 coveralls 或 codecov.io 添加代码覆盖支持是微不足道的。

关于testing - 是否可以在 Julia 中组织健全性检查,以便在加载包时轻松编译它们?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36485092/

相关文章:

docker - 在 dockerfile 和 CI 中运行构建和测试?

c++ - 如何在 Visual Studio 2013 的 Debug模式下关闭 ASSERT

unit-testing - 我是否应该在类中添加功能只是为了使其可测试?

java - 如何获取Android设备ID?

plot - 在 Julia 中,绘制具有特定子标签的图形

function - Julia - 使用元编程定义多个函数

objective-c - 在 swift assert(0) 中无法将 Int 类型的值转换为预期的参数类型 Bool

exception-handling - 为什么我应该在 Sitecore 中使用 Assert.IsNull?

Django 测试 - 如何为特定应用程序使用不同的设置文件运行测试?

Julia:读取工作目录中的许多文件