编写测试集
Version >= 0.5.0
在版本 v0.5 中,测试集内置于标准库 Base.Test
模块中,你无需执行任何特殊操作(除了 using Base.Test
)以使用它们。
Version = 0.4.0
测试集不是 Julia v0.4 的 Base.Test
库的一部分。相反,你必须 REQUIRE
BaseTestNext
模块,并将 using BaseTestNext
添加到你的文件。要支持版本 0.4 和 0.5,你可以使用
if VERSION ≥ v"0.5.0-dev+7720"
using Base.Test
else
using BaseTestNext
const Test = BaseTestNext
end
在测试集中将相关的 @test
组合在一起是有帮助的。除了更清晰的测试组织,测试集还提供更好的输出和更多的可定制性。
要定义测试集,只需使用 @testset
块包装任意数量的 @test
:
@testset "+" begin
@test 1 + 1 == 2
@test 2 + 2 == 4
end
@testset "*" begin
@test 1 * 1 == 1
@test 2 * 2 == 4
end
运行这些测试集将打印以下输出:
Test Summary: | Pass Total
+ | 2 2
Test Summary: | Pass Total
* | 2 2
即使测试集包含失败的测试,整个测试集也将运行完成,并且将记录并报告失败:
@testset "-" begin
@test 1 - 1 == 0
@test 2 - 2 == 1
@test 3 - () == 3
@test 4 - 4 == 0
end
运行此测试集会导致
-: Test Failed
Expression: 2 - 2 == 1
Evaluated: 0 == 1
in record(::Base.Test.DefaultTestSet, ::Base.Test.Fail) at ./test.jl:428
...
-: Error During Test
Test threw an exception of type MethodError
Expression: 3 - () == 3
MethodError: no method matching -(::Int64, ::Tuple{})
...
Test Summary: | Pass Fail Error Total
- | 2 1 1 4
ERROR: Some tests did not pass: 2 passed, 1 failed, 1 errored, 0 broken.
...
测试集可以嵌套,允许任意深度组织
@testset "Int" begin
@testset "+" begin
@test 1 + 1 == 2
@test 2 + 2 == 4
end
@testset "-" begin
@test 1 - 1 == 0
end
end
如果测试通过,那么这将只显示最外层测试集的结果:
Test Summary: | Pass Total
Int | 3 3
但是如果测试失败,则会报告深入到确切的测试集并导致失败的测试。
@testset
宏可与 for
循环一起使用,一次创建多个测试集:
@testset for i in 1:5
@test 2i == i + i
@test i^2 == i * i
@test i ÷ i == 1
end
报道
Test Summary: | Pass Total
i = 1 | 3 3
Test Summary: | Pass Total
i = 2 | 3 3
Test Summary: | Pass Total
i = 3 | 3 3
Test Summary: | Pass Total
i = 4 | 3 3
Test Summary: | Pass Total
i = 5 | 3 3
常见的结构是使外部测试集测试组件或类型。在这些外部测试集中,内部测试集测试行为。例如,假设我们创建了一个类型 UniversalSet
,其中包含一个包含所有内容的单例实例。在我们实现类型之前,我们可以使用测试驱动的开发原则并实现测试:
@testset "UniversalSet" begin
U = UniversalSet.instance
@testset "egal/equal" begin
@test U === U
@test U == U
end
@testset "in" begin
@test 1 in U
@test "Hello World" in U
@test Int in U
@test U in U
end
@testset "subset" begin
@test Set() ⊆ U
@test Set(["Hello World"]) ⊆ U
@test Set(1:10) ⊆ U
@test Set([:a, 2.0, "w", Set()]) ⊆ U
@test U ⊆ U
end
end
然后我们可以开始实现我们的功能,直到它通过测试。第一步是定义类型:
immutable UniversalSet <: Base.AbstractSet end
我们现在只有两个测试通过。我们可以实现 in
:
immutable UniversalSet <: Base.AbstractSet end
Base.in(x, ::UniversalSet) = true
这也使我们的一些子集测试通过。然而,issubset
(⊆
)回退对 UniversalSet
不起作用,因为回退试图迭代元素,这是我们做不到的。我们可以简单地定义一个特殊化,使得 issubset
可以为任何集合返回 true
:
immutable UniversalSet <: Base.AbstractSet end
Base.in(x, ::UniversalSet) = true
Base.issubset(x::Base.AbstractSet, ::UniversalSet) = true
现在,我们所有的测试都通过了!