Julia Language
ユニットテスト
サーチ…
構文
- @test [expr]
- @test_throws [例外] [expr]
- @testset "[name]" begin; [テスト];終わり
- Pkg.test([package])
備考
Base.Test
の標準ライブラリー資料には、これらの例に示されている以上の追加資料が含まれています。
パッケージのテスト
パッケージの単体テストを実行するには、 Pkg.test
関数を使用します。 MyPackage
という名前のパッケージの場合、コマンドは次のようになります。
julia> Pkg.test("MyPackage")
期待される出力は次のようになります。
INFO: Computing test dependencies for MyPackage...
INFO: Installing BaseTestNext v0.2.2
INFO: Testing MyPackage
Test Summary: | Pass Total
Data | 66 66
Test Summary: | Pass Total
Monetary | 107 107
Test Summary: | Pass Total
Basket | 47 47
Test Summary: | Pass Total
Mixed | 13 13
Test Summary: | Pass Total
Data Access | 35 35
INFO: MyPackage tests passed
INFO: Removing BaseTestNext v0.2.2
明らかに、異なるパッケージが異なるフレームワークを使用するため、上記と正確に一致するとは期待できません。
このコマンドは、クリーンな環境でパッケージのtest/runtests.jl
ファイルを実行します。
インストールされたすべてのパッケージを一度にテストできます。
julia> Pkg.test()
しかし、これは通常、非常に長い時間がかかります。
簡単なテストの作成
ユニットテストはパッケージ内のtest/runtests.jl
ファイルで宣言されています。通常、このファイルは
using MyModule
using Base.Test
テストの基本単位は@test
マクロです。このマクロは一種のアサーションのようなものです。ブール式は@test
マクロでテストできます:
@test 1 + 1 == 2
@test iseven(10)
@test 9 < 10 || 10 < 9
私たちはREPLで@test
マクロを試すことができます:
julia> using Base.Test
julia> @test 1 + 1 == 2
Test Passed
Expression: 1 + 1 == 2
Evaluated: 2 == 2
julia> @test 1 + 1 == 3
Test Failed
Expression: 1 + 1 == 3
Evaluated: 2 == 3
ERROR: There was an error during testing
in record(::Base.Test.FallbackTestSet, ::Base.Test.Fail) at ./test.jl:397
in do_test(::Base.Test.Returned, ::Expr) at ./test.jl:281
テストマクロは、ループや関数など、どこからでも使用できます。
# For positive integers, a number's square is at least as large as the number
for i in 1:10
@test i^2 ≥ i
end
# Test that no two of a, b, or c share a prime factor
function check_pairwise_coprime(a, b, c)
@test gcd(a, b) == 1
@test gcd(a, c) == 1
@test gcd(b, c) == 1
end
check_pairwise_coprime(10, 23, 119)
テストセットの作成
バージョンv0.5では、テストセットは標準ライブラリのBase.Test
モジュールに組み込まれており、 using Base.Test
を使用する以外に特別な操作を行う必要はありません。
テストセットは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
テストセットにまとめると@test
です。より明確なテスト構成に加えて、テストセットはより良い出力とカスタマイズ性を提供します。
テストセットを定義するには、任意の数の@test
を@testset
ブロックで@testset
ます:
@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
私たちのテストのうち2つだけが今すぐ通過します。私たちは以下を実装in
ことができます:
immutable UniversalSet <: Base.AbstractSet end
Base.in(x, ::UniversalSet) = true
これはまた、私たちのサブセットテストのいくつかを合格させます。しかし、fallbackは要素に対して反復しようとするため、 issubset
( ⊆
)fallbackはUniversalSet
では機能しません。すべてのセットに対してissubset
true
に戻す特殊化を定義することは簡単です。
immutable UniversalSet <: Base.AbstractSet end
Base.in(x, ::UniversalSet) = true
Base.issubset(x::Base.AbstractSet, ::UniversalSet) = true
そして、今、私たちのテストはすべてパスします!
例外のテスト
テストの実行中に発生した例外はテストに失敗し、テストがテストセットに含まれていない場合は、テストエンジンを終了します。ほとんどの場合、例外は望ましい結果ではないため、通常、これは良いことです。しかし、時には、特定の例外が発生したことを具体的にテストしたい場合もあります。 @test_throws
マクロはこれを容易にします。
julia> @test_throws BoundsError [1, 2, 3][4]
Test Passed
Expression: ([1,2,3])[4]
Thrown: BoundsError
間違った例外がスローされた場合、 @test_throws
は失敗します。
julia> @test_throws TypeError [1, 2, 3][4]
Test Failed
Expression: ([1,2,3])[4]
Expected: TypeError
Thrown: BoundsError
ERROR: There was an error during testing
in record(::Base.Test.FallbackTestSet, ::Base.Test.Fail) at ./test.jl:397
in do_test_throws(::Base.Test.Threw, ::Expr, ::Type{T}) at ./test.jl:329
例外がスローされない場合、 @test_throws
も失敗します:
julia> @test_throws BoundsError [1, 2, 3, 4][4]
Test Failed
Expression: ([1,2,3,4])[4]
Expected: BoundsError
No exception thrown
ERROR: There was an error during testing
in record(::Base.Test.FallbackTestSet, ::Base.Test.Fail) at ./test.jl:397
in do_test_throws(::Base.Test.Returned, ::Expr, ::Type{T}) at ./test.jl:329
浮動小数点の近似等価のテスト
次のような取引は何ですか?
julia> @test 0.1 + 0.2 == 0.3
Test Failed
Expression: 0.1 + 0.2 == 0.3
Evaluated: 0.30000000000000004 == 0.3
ERROR: There was an error during testing
in record(::Base.Test.FallbackTestSet, ::Base.Test.Fail) at ./test.jl:397
in do_test(::Base.Test.Returned, ::Expr) at ./test.jl:281
誤差は、のいずれことに起因する0.1
、 0.2
、及び0.3
-丁度それらの値としてコンピュータで表現される1//10
、 2//10
、及び3//10
。代わりに、それらは非常に近い値で近似されます。しかし、上のテストの失敗に見られるように、2つの近似を足し合わせると、結果は可能なものよりもわずかに悪い近似になる可能性があります。ここで扱うことができないこのテーマにははるかに多くがあります。
しかし、運が悪いわけではありません!浮動小数点数と浮動小数点演算への丸めの組み合わせがほぼ正確であることをテストするために、正確でない場合でもisapprox
関数(演算子≈
対応)を使用できます。だから私たちはテストを書き直すことができます
julia> @test 0.1 + 0.2 ≈ 0.3
Test Passed
Expression: 0.1 + 0.2 ≈ 0.3
Evaluated: 0.30000000000000004 isapprox 0.3
もちろん、もし私たちのコードが完全に間違っていたとしても、テストはそれを引き継いでいます:
julia> @test 0.1 + 0.2 ≈ 0.4
Test Failed
Expression: 0.1 + 0.2 ≈ 0.4
Evaluated: 0.30000000000000004 isapprox 0.4
ERROR: There was an error during testing
in record(::Base.Test.FallbackTestSet, ::Base.Test.Fail) at ./test.jl:397
in do_test(::Base.Test.Returned, ::Expr) at ./test.jl:281
isapprox
関数は、浮動小数点型の数値と精度のサイズに基づいたヒューリスティックを使用して、許容されるエラーの量を決定します。これはすべての状況に適しているわけではありませんが、ほとんどの場合に機能し、独自のバージョンのisapprox
実装するために多くの労力を節約します。