Unit and Functional Testing¶
Testing Base Julia¶
Julia is under rapid development and has an extensive test suite to
verify functionality across multiple platforms. If you build Julia
from source, you can run this test suite with maketest
. In a
binary install, you can run the test suite using Base.runtests()
.
runtests
([tests=["all"][, numcores=iceil(CPU_CORES/2)]])¶Run the Julia unit tests listed in
tests
, which can be either a string or an array of strings, usingnumcores
processors. (not exported)
Test Framework¶
The Test
module contains macros and functions related to testing.
A default handler is provided to run the tests, and a custom one can be
provided by the user by using the registerhandler()
function.
To use the default handler, the macro @test()
can be used directly:
julia>usingBase.Testjulia>@test1==1julia>@test1==0ERROR:testfailed:1==0inerroraterror.jl:21indefault_handlerattest.jl:19indo_testattest.jl:39julia>@testerror("This is what happens when a test fails")ERROR:testerrorduringerror("This is what happens when a test fails")Thisiswhathappenswhenatestfailsinerroraterror.jl:21inanonymousattest.jl:62indo_testattest.jl:37
As seen in the examples above, failures or errors will print the abstract syntax tree of the expression in question.
Another macro is provided to check if the given expression throws an exception of type extype
,
@test_throws()
:
julia>@test_throwsErrorExceptionerror("An error")ErrorException("An error")julia>@test_throwsBoundsErrorerror("An error")ERROR:testfailed:error("An error")inerroraterror.jl:21indefault_handlerattest.jl:19indo_test_throwsattest.jl:55julia>@test_throwsDomainErrorthrow(DomainError())DomainError()julia>@test_throwsDomainErrorthrow(EOFError())ERROR:testfailed:throw(EOFError())inerroraterror.jl:21indefault_handlerattest.jl:19indo_test_throwsattest.jl:55
As floating-point values can be imprecise, you can perform approximate
equality checks using either @testa≈b
(where ≈
, typed via
tab completion of \approx
, is the isapprox
function) or use
the macros @test_approx_eq
macro (which differs from isapprox
in that it treats NaN values as equal and has a smaller default
tolerance) or @test_approx_eq_eps
(which takes an extra argument
indicating the relative tolerance):
julia>@test1≈0.999999999julia>@test1≈0.999999ERROR:testfailed:1isapprox0.999999inexpression:1≈0.999999inerroraterror.jl:21indefault_handlerattest.jl:30indo_testattest.jl:53julia>@test_approx_eq1.0.999999999ERROR:assertionfailed:|1.0-0.999999999|<2.220446049250313e-121.0=1.00.999999999=0.999999999intest_approx_eqattest.jl:75intest_approx_eqattest.jl:80julia>@test_approx_eq1.0.9999999999999julia>@test_approx_eq_eps1.0.9991e-2julia>@test_approx_eq_eps1.0.9991e-3ERROR:assertionfailed:|1.0-0.999|<=0.0011.0=1.00.999=0.999difference=0.0010000000000000009>0.001inerroraterror.jl:22intest_approx_eqattest.jl:68
Handlers¶
A handler is a function defined for three kinds of arguments: Success
, Failure
, Error
:
# An example definition of a test handlertest_handler(r::Success)=nothingtest_handler(r::Failure)=error("test failed: $(r.expr)")test_handler(r::Error)=rethrow(r)
A different handler can be used for a block (with with_handler()
):
julia>usingBase.Testjulia>custom_handler(r::Test.Success)=println("Success on $(r.expr)")custom_handler(genericfunction with1method)julia>custom_handler(r::Test.Failure)=error("Error on custom handler: $(r.expr)")custom_handler(genericfunction with2methods)julia>custom_handler(r::Test.Error)=rethrow(r)custom_handler(genericfunction with3methods)julia>Test.with_handler(custom_handler)do@test1==1@test1!=1endSuccesson:((1==1))ERROR:Erroroncustomhandler::((1!=1))inerroraterror.jl:21incustom_handleratnone:1indo_testattest.jl:39inanonymousatnofile:3intask_local_storageattask.jl:28inwith_handlerattest.jl:24
The Success
and Failure
types include an additonal field, resultexpr
, which is a partially evaluated expression. For example, in a comparison it will contain an expression with the left and right sides evaluated.
Macros¶
@test
(ex)¶Test the expression
ex
and calls the current handler to handle the result.
@test_throws
(extype, ex)¶Test that the expression
ex
throws an exception of typeextype
and calls the current handler to handle the result.
@test_approx_eq
(a, b)¶Test two floating point numbers
a
andb
for equality taking in account small numerical errors.
@test_approx_eq_eps
(a, b, tol)¶Test two floating point numbers
a
andb
for equality taking in account a margin of tolerance given bytol
.
@inferred f(x)
Tests that the call expression
f(x)
returns a value of the same type inferred by the compiler. It’s useful to check for type stability.f(x)
can be any call expression. Returns the result off(x)
if the types match, and anError
Result
if it finds different types.julia>usingBase.Testjulia>f(a,b,c)=b>1?1:1.0f(genericfunction with1method)julia>typeof(f(1,2,3))Int64julia>@code_warntypef(1,2,3)Variables:a::Int64b::Int64c::Int64Body:begin# none, line 1:unless(Base.slt_int)(1,b::Int64)::Boolgoto0return10:return1.0end::UNION{FLOAT64,INT64}julia>@inferredf(1,2,3)ERROR:returntype Int64doesnotmatchinferredreturntype Union{Float64,Int64}inerrorat./error.jl:21julia>@inferredmax(1,2)2