Unit Testing
Testing Base Julia
Julia, hızlı bir geliştirme sürecindedir ve birden fazla platformda işlevselliği doğrulamak için kapsamlı bir test paketi bulunmaktadır. Eğer Julia'yı kaynak kodundan derlerseniz, bu test paketini make test
komutuyla çalıştırabilirsiniz. Bir ikili kurulumda ise test paketini Base.runtests()
kullanarak çalıştırabilirsiniz.
Base.runtests
— FunctionBase.runtests(tests=["all"]; ncores=ceil(Int, Sys.CPU_THREADS / 2),
exit_on_error=false, revise=false, [seed])
tests
içinde listelenen Julia birim testlerini çalıştırın; bu, bir dize veya dizeler dizisi olabilir ve ncores
işlemcisi kullanır. exit_on_error
false
ise, bir test başarısız olduğunda, diğer dosyalardaki tüm kalan testler yine de çalıştırılacaktır; aksi takdirde, exit_on_error == true
olduğunda atlanır. revise
true
ise, testler çalıştırılmadan önce Base
veya standart kütüphanelerdeki herhangi bir değişikliği yüklemek için Revise
paketi kullanılır. Eğer bir tohum anahtar argümanı aracılığıyla sağlanmışsa, bu, testlerin çalıştırıldığı bağlamda küresel RNG'yi tohumlamak için kullanılır; aksi takdirde tohum rastgele seçilir.
Basic Unit Tests
Test
modülü basit birim testi işlevselliği sağlar. Birim testi, kodunuzun doğru olup olmadığını görmek için sonuçların beklediğiniz gibi olup olmadığını kontrol etmenin bir yoludur. Değişiklikler yaptıktan sonra kodunuzun hala çalıştığından emin olmak için yararlı olabilir ve tamamlandığında kodunuzun sahip olması gereken davranışları belirtmek için geliştirme sırasında kullanılabilir. Ayrıca, adding tests to your Julia Package için belgeleri de incelemek isteyebilirsiniz.
Basit bir birim testi @test
ve @test_throws
makroları ile gerçekleştirilebilir:
Test.@test
— Macro@test ex
@test f(args...) key=val ...
@test ex broken=true
@test ex skip=true
ex
ifadesinin true
değerine eşit olduğunu test edin. Eğer bir @testset
içinde çalıştırılırsa, true
ise Pass
Result
döndürün, false
ise Fail
Result
döndürün ve değerlendirilemezse Error
Result
döndürün. Eğer bir @testset
dışında çalıştırılırsa, Fail
veya Error
döndürmek yerine bir istisna fırlatın.
Örnekler
julia> @test true
Test Geçti
julia> @test [1, 2] + [2, 1] == [3, 3]
Test Geçti
@test f(args...) key=val...
biçimi, @test f(args..., key=val...)
yazmakla eşdeğerdir ve bu, ifadenin yaklaşık karşılaştırmalar gibi infiks sözdizimi kullanan bir çağrı olması durumunda yararlı olabilir:
julia> @test π ≈ 3.14 atol=0.01
Test Geçti
Bu, daha çirkin bir test olan @test ≈(π, 3.14, atol=0.01)
ile eşdeğerdir. İlk ifade bir çağrı ifadesi olmadıkça birden fazla ifade sağlamak bir hatadır ve geri kalanlar atama (k=v
) olmalıdır.
key=val
argümanları için herhangi bir anahtar kullanabilirsiniz, ancak broken
ve skip
anahtarları, @test
bağlamında özel anlamlara sahiptir:
broken=cond
,cond==true
olduğunda geçmesi gereken ancak şu anda sürekli olarak başarısız olan bir testi belirtir.ex
ifadesininfalse
değerine eşit olduğunu veya bir istisna oluşturduğunu test eder. Eğer öyleyseBroken
Result
döndürür veya ifadetrue
değerine eşit olursaError
Result
döndürür.cond==false
olduğunda normal@test ex
değerlendirilir.skip=cond
,cond==true
olduğunda çalıştırılmaması gereken ancak test özeti raporlamasındaBroken
olarak dahil edilmesi gereken bir testi işaretler. Bu, aralıklı olarak başarısız olan testler veya henüz uygulanmamış işlevsellik testleri için yararlı olabilir.cond==false
olduğunda normal@test ex
değerlendirilir.
Örnekler
julia> @test 2 + 2 ≈ 6 atol=1 broken=true
Test Bozuk
İfade: ≈(2 + 2, 6, atol = 1)
julia> @test 2 + 2 ≈ 5 atol=1 broken=false
Test Geçti
julia> @test 2 + 2 == 5 skip=true
Test Bozuk
Atlandı: 2 + 2 == 5
julia> @test 2 + 2 == 4 skip=false
Test Geçti
broken
ve skip
anahtar argümanları en az Julia 1.7 gerektirir.
Test.@test_throws
— Macro@test_throws exception expr
expr
ifadesinin exception
fırlattığını test eder. İstisna, görüntülenen hata mesajında meydana gelen bir tür, bir dize, düzenli ifade veya dize listesini belirtebilir, bir eşleşme fonksiyonu veya bir değer (alanları karşılaştırarak eşitlik için test edilecektir) olabilir. @test_throws
'ın bir son anahtar biçimini desteklemediğini unutmayın.
exception
olarak bir tür veya değer dışında bir şey belirtme yeteneği, Julia v1.8 veya daha yenisini gerektirir.
Örnekler
julia> @test_throws BoundsError [1, 2, 3][4]
Test Passed
Thrown: BoundsError
julia> @test_throws DimensionMismatch [1, 2, 3] + [1, 2]
Test Passed
Thrown: DimensionMismatch
julia> @test_throws "Try sqrt(Complex" sqrt(-1)
Test Passed
Message: "DomainError with -1.0:\nsqrt was called with a negative real argument but will only return a complex result if called with a complex argument. Try sqrt(Complex(x))."
Son örnekte, tek bir dize ile eşleşmek yerine alternatif olarak şu şekilde yapılabilirdi:
["Try", "Complex"]
(bir dize listesi)r"Try sqrt\([Cc]omplex"
(bir düzenli ifade)str -> occursin("complex", str)
(bir eşleşme fonksiyonu)
Örneğin, yeni fonksiyonumuzun foo(x)
beklenildiği gibi çalışıp çalışmadığını kontrol etmek istiyoruz:
julia> using Test
julia> foo(x) = length(x)^2
foo (generic function with 1 method)
Eğer koşul doğruysa, bir Pass
döndürülür:
julia> @test foo("bar") == 9
Test Passed
julia> @test foo("fizz") >= 10
Test Passed
Eğer koşul yanlışsa, o zaman bir Fail
döndürülür ve bir istisna fırlatılır:
julia> @test foo("f") == 20
Test Failed at none:1
Expression: foo("f") == 20
Evaluated: 1 == 20
ERROR: There was an error during testing
Eğer bir istisna fırlatıldığı için koşul değerlendirilemezse, bu durumda length
semboller için tanımlı olmadığı için bir Error
nesnesi döndürülür ve bir istisna fırlatılır:
julia> @test foo(:cat) == 1
Error During Test
Test threw an exception of type MethodError
Expression: foo(:cat) == 1
MethodError: no method matching length(::Symbol)
The function `length` exists, but no method is defined for this combination of argument types.
Closest candidates are:
length(::SimpleVector) at essentials.jl:256
length(::Base.MethodList) at reflection.jl:521
length(::MethodTable) at reflection.jl:597
...
Stacktrace:
[...]
ERROR: There was an error during testing
Eğer bir ifadenin bir istisna fırlatmasını bekliyorsak, bunun gerçekleşip gerçekleşmediğini kontrol etmek için @test_throws
kullanabiliriz:
julia> @test_throws MethodError foo(:cat)
Test Passed
Thrown: MethodError
Working with Test Sets
Genellikle, işlevlerin bir dizi girdi üzerinde doğru çalıştığından emin olmak için çok sayıda test kullanılır. Bir test başarısız olduğunda, varsayılan davranış hemen bir istisna fırlatmaktır. Ancak, testlerin geri kalanını önce çalıştırmak, test edilen kodda ne kadar hata olduğunu daha iyi anlamak için genellikle tercih edilir.
@testset
testleri çalıştırıldığında kendi yerel kapsamını oluşturacaktır.
@testset
makrosu, testleri setler halinde gruplamak için kullanılabilir. Bir test setindeki tüm testler çalıştırılacak ve test setinin sonunda bir özet yazdırılacaktır. Eğer testlerden herhangi biri başarısız olursa veya bir hata nedeniyle değerlendirilemezse, test seti bir TestSetException
fırlatacaktır.
Test.@testset
— Macro@testset [ÖzelTestSet] [seçenekler...] ["açıklama"] begin test_ex end
@testset [ÖzelTestSet] [seçenekler...] ["açıklama $v"] for v in itr test_ex end
@testset [ÖzelTestSet] [seçenekler...] ["açıklama $v, $w"] for v in itrv, w in itrw test_ex end
@testset [ÖzelTestSet] [seçenekler...] ["açıklama"] test_func()
@testset let v = v, w = w; test_ex; end
begin/end veya fonksiyon çağrısı ile
@testset kullanıldığında, begin/end veya tek bir fonksiyon çağrısı ile, makro verilen ifadeyi değerlendirmek için yeni bir test seti başlatır.
Eğer özel bir test seti türü verilmezse, varsayılan olarak DefaultTestSet
oluşturulur. DefaultTestSet
, tüm sonuçları kaydeder ve eğer herhangi bir Fail
veya Error
varsa, üst düzey (iç içe olmayan) test setinin sonunda bir istisna fırlatır ve test sonuçlarının bir özetini sunar.
Herhangi bir özel test seti türü ( AbstractTestSet
alt türü) verilebilir ve bu, iç içe @testset
çağrıları için de kullanılacaktır. Verilen seçenekler yalnızca verildikleri test setine uygulanır. Varsayılan test seti türü üç boolean seçeneği kabul eder:
verbose
:true
ise, iç içe test setlerinin sonuç özeti, hepsi geçtiğinde bile gösterilir (varsayılanfalse
).showtiming
:true
ise, her gösterilen test setinin süresi gösterilir (varsayılantrue
).failfast
:true
ise, herhangi bir test hatası veya hatası, test setinin ve herhangi bir alt test setinin hemen dönmesine neden olur (varsayılanfalse
). Bu, ayrıcaJULIA_TEST_FAILFAST
ortam değişkeni aracılığıyla küresel olarak ayarlanabilir.
@testset test_func()
en az Julia 1.8 gerektirir.
failfast
en az Julia 1.9 gerektirir.
Açıklama dizesi döngü indekslerinden interpolasyonu kabul eder. Eğer açıklama sağlanmazsa, değişkenlere dayalı olarak bir tane oluşturulur. Eğer bir fonksiyon çağrısı sağlanırsa, adı kullanılacaktır. Açık açıklama dizeleri bu davranışı geçersiz kılar.
Varsayılan olarak @testset
makrosu test seti nesnesinin kendisini döndürecektir, ancak bu davranış diğer test seti türlerinde özelleştirilebilir. Eğer bir for
döngüsü kullanılıyorsa, makro finish
yönteminin döndürdüğü değerlerin bir listesini toplar ve döndürür; bu, varsayılan olarak her yinelemede kullanılan test seti nesnelerinin bir listesini döndürecektir.
@testset
gövdesinin yürütülmesinden önce, Random.seed!(seed)
'e örtük bir çağrı vardır; burada seed
, küresel RNG'nin mevcut tohumudur. Ayrıca, gövdenin yürütülmesinden sonra, küresel RNG'nin durumu @testset
öncesindeki haline geri yüklenir. Bu, başarısızlık durumunda yeniden üretilebilirliği kolaylaştırmak ve @testset
'lerin küresel RNG durumu üzerindeki yan etkilerine bakılmaksızın sorunsuz yeniden düzenlenmesine izin vermek içindir.
Örnekler
julia> @testset "trigonometric identities" begin
θ = 2/3*π
@test sin(-θ) ≈ -sin(θ)
@test cos(-θ) ≈ cos(θ)
@test sin(2θ) ≈ 2*sin(θ)*cos(θ)
@test cos(2θ) ≈ cos(θ)^2 - sin(θ)^2
end;
Test Summary: | Pass Total Time
trigonometric identities | 4 4 0.2s
@testset for
@testset for
kullanıldığında, makro sağlanan döngünün her yinelemesi için yeni bir test başlatır. Her test setinin anlamı, begin/end
durumundaki ile aynıdır (her döngü yinelemesi için kullanılmış gibi).
@testset let
@testset let
kullanıldığında, makro verilen nesneyi içindeki herhangi bir başarısız test için bir bağlam nesnesi olarak ekleyerek şeffaf bir test seti başlatır. Bu, bir büyük nesne üzerinde bir dizi ilgili test gerçekleştirirken ve bireysel testlerden herhangi biri başarısız olduğunda bu büyük nesneyi yazdırmak istenildiğinde faydalıdır. Şeffaf test setleri, test seti hiyerarşisinde ek iç içe katmanlar oluşturmaz ve doğrudan üst test setine geçilir (bağlam nesnesi herhangi bir başarısız testin yanına eklenir).
@testset let
en az Julia 1.9 gerektirir.
Birden fazla let
ataması, Julia 1.10'dan itibaren desteklenmektedir.
Örnekler
julia> @testset let logi = log(im)
@test imag(logi) == π/2
@test !iszero(real(logi))
end
Test Failed at none:3
Expression: !(iszero(real(logi)))
Context: logi = 0.0 + 1.5707963267948966im
HATA: Test sırasında bir hata oluştu
julia> @testset let logi = log(im), op = !iszero
@test imag(logi) == π/2
@test op(real(logi))
end
Test Failed at none:3
Expression: op(real(logi))
Context: logi = 0.0 + 1.5707963267948966im
op = !iszero
HATA: Test sırasında bir hata oluştu
Test.TestSetException
— TypeTestSetException
Bir test seti tamamlandığında ve tüm testler geçmediğinde fırlatılır.
foo(x)
fonksiyonu için testlerimizi bir test setine koyabiliriz:
julia> @testset "Foo Tests" begin
@test foo("a") == 1
@test foo("ab") == 4
@test foo("abc") == 9
end;
Test Summary: | Pass Total Time
Foo Tests | 3 3 0.0s
Test setleri de iç içe olabilir:
julia> @testset "Foo Tests" begin
@testset "Animals" begin
@test foo("cat") == 9
@test foo("dog") == foo("cat")
end
@testset "Arrays $i" for i in 1:3
@test foo(zeros(i)) == i^2
@test foo(fill(1.0, i)) == i^2
end
end;
Test Summary: | Pass Total Time
Foo Tests | 8 8 0.0s
Fonksiyonları çağırmanın yanı sıra:
julia> f(x) = @test isone(x)
f (generic function with 1 method)
julia> @testset f(1);
Test Summary: | Pass Total Time
f | 1 1 0.0s
Bu, test setlerinin faktörleştirilmesine olanak tanımak için kullanılabilir, böylece ilişkili fonksiyonları çalıştırarak bireysel test setlerini çalıştırmak daha kolay hale gelir. Fonksiyonlar durumunda, test setine çağrılan fonksiyonun adı verilecektir. Eğer iç içe geçmiş bir test setinin hatası yoksa, burada olduğu gibi, verbose=true
seçeneği geçilmedikçe özet içinde gizlenecektir:
julia> @testset verbose = true "Foo Tests" begin
@testset "Animals" begin
@test foo("cat") == 9
@test foo("dog") == foo("cat")
end
@testset "Arrays $i" for i in 1:3
@test foo(zeros(i)) == i^2
@test foo(fill(1.0, i)) == i^2
end
end;
Test Summary: | Pass Total Time
Foo Tests | 8 8 0.0s
Animals | 2 2 0.0s
Arrays 1 | 2 2 0.0s
Arrays 2 | 2 2 0.0s
Arrays 3 | 2 2 0.0s
Eğer bir test hatası alırsak, yalnızca başarısız olan test setlerinin detayları gösterilecektir:
julia> @testset "Foo Tests" begin
@testset "Animals" begin
@testset "Felines" begin
@test foo("cat") == 9
end
@testset "Canines" begin
@test foo("dog") == 9
end
end
@testset "Arrays" begin
@test foo(zeros(2)) == 4
@test foo(fill(1.0, 4)) == 15
end
end
Arrays: Test Failed
Expression: foo(fill(1.0, 4)) == 15
Evaluated: 16 == 15
[...]
Test Summary: | Pass Fail Total Time
Foo Tests | 3 1 4 0.0s
Animals | 2 2 0.0s
Arrays | 1 1 2 0.0s
ERROR: Some tests did not pass: 3 passed, 1 failed, 0 errored, 0 broken.
Testing Log Statements
Bir @test_logs
makrosunu log ifadelerini test etmek için kullanabilir veya TestLogger
kullanabilirsiniz.
Test.@test_logs
— Macro@test_logs [log_patterns...] [keywords] ifade
ifade
tarafından üretilen log kayıtlarının bir listesini collect_test_logs
kullanarak toplayın, bunların log_patterns
dizisine uyduğunu kontrol edin ve ifade
değerini döndürün. keywords
log kayıtlarının basit bir filtrelemesini sağlar: min_level
anahtarı, test için toplanacak minimum log seviyesini kontrol eder, match_mode
anahtarı eşleşmenin nasıl yapılacağını tanımlar (varsayılan :all
, tüm logların ve desenlerin çiftler halinde eşleştiğini kontrol eder; :any
kullanarak desenin dizide en az bir yerde eşleşip eşleşmediğini kontrol edebilirsiniz.)
En kullanışlı log deseni, (level,message)
biçiminde basit bir demettir. Diğer log meta verilerini eşleştirmek için farklı sayıda demet elemanı kullanılabilir; bu, handle_message
fonksiyonu aracılığıyla AbstractLogger
'a geçirilen argümanlara karşılık gelir: (level,message,module,group,id,file,line)
. Mevcut olan elemanlar, varsayılan olarak ==
kullanılarak log kaydı alanlarıyla çiftler halinde eşleştirilecektir; Symbol
'lerin standart log seviyeleri için kullanılabileceği ve desendeki Regex
'lerin string veya Symbol alanlarıyla occursin
kullanarak eşleşeceği özel durumlar vardır.
Örnekler
Bir uyarı kaydeden ve birkaç debug mesajı üreten bir fonksiyonu düşünün:
function foo(n)
@info "Doing foo with n=$n"
for i=1:n
@debug "Iteration $i"
end
42
end
Info mesajını test edebiliriz:
@test_logs (:info,"Doing foo with n=2") foo(2)
Eğer debug mesajlarını da test etmek istiyorsak, bunların min_level
anahtarı ile etkinleştirilmesi gerekir:
using Logging
@test_logs (:info,"Doing foo with n=2") (:debug,"Iteration 1") (:debug,"Iteration 2") min_level=Logging.Debug foo(2)
Belirli mesajların üretilip üretilmediğini test etmek istiyorsanız, match_mode=:any
anahtarını ayarlayabilirsiniz:
using Logging
@test_logs (:info,) (:debug,"Iteration 42") min_level=Logging.Debug match_mode=:any foo(100)
Makro, döndürülen değeri de test etmek için @test
ile zincirlenebilir:
@test (@test_logs (:info,"Doing foo with n=2") foo(2)) == 42
Uyarıların yokluğunu test etmek istiyorsanız, log desenlerini belirtmeyi atlayabilir ve min_level
'i buna göre ayarlayabilirsiniz:
# logger seviyesi uyarı olduğunda ifadenin hiçbir mesaj kaydetmediğini test edin:
@test_logs min_level=Logging.Warn @info("Some information") # geçer
@test_logs min_level=Logging.Warn @warn("Some information") # başarısız
@warn
tarafından üretilmeyen stderr
içinde uyarıların (veya hata mesajlarının) yokluğunu test etmek istiyorsanız, @test_nowarn
bakın. ```
Test.TestLogger
— TypeTestLogger(; min_level=Info, catch_exceptions=false)
logs::Vector{LogRecord}
alanında kaydedilen mesajları yakalayan bir TestLogger
oluşturun.
LogLevel
'ı kontrol etmek için min_level
'i, log olayı oluşturma sırasında atılan istisnaların yakalanıp yakalanmayacağını belirlemek için catch_exceptions
'ı ve en fazla n
kez loglama konvansiyonunu takip edip etmeyeceğini belirlemek için respect_maxlog
'ı ayarlayın.
Ayrıca bkz: LogRecord
.
Örnekler
julia> using Test, Logging
julia> f() = @info "Merhaba" number=5;
julia> test_logger = TestLogger();
julia> with_logger(test_logger) do
f()
@info "Hoşça kal!"
end
julia> @test test_logger.logs[1].message == "Merhaba"
Test Passed
julia> @test test_logger.logs[1].kwargs[:number] == 5
Test Passed
julia> @test test_logger.logs[2].message == "Hoşça kal!"
Test Passed
Test.LogRecord
— TypeLogRecord
Tek bir günlük olayının sonuçlarını saklar. Alanlar:
level
: günlük mesajınınLogLevel
seviyesimessage
: günlük mesajının metinsel içeriği_module
: günlük olayının modülügroup
: günlük grubu (varsayılan olarak, günlük olayını içeren dosyanın adı)id
: günlük olayının kimliğifile
: günlük olayını içeren dosyaline
: günlük olayının dosya içindeki satırıkwargs
: günlük olayına geçirilen herhangi bir anahtar kelime argümanı
Other Test Macros
Hesaplamalar kayan nokta değerleri üzerinde kesin olmayabileceğinden, yaklaşık eşitlik kontrollerini ya @test a ≈ b
kullanarak (burada ≈
, \approx
'ın sekme tamamlama ile yazıldığı) ya da doğrudan isapprox
kullanarak gerçekleştirebilirsiniz.
julia> @test 1 ≈ 0.999999999
Test Passed
julia> @test 1 ≈ 0.999999
Test Failed at none:1
Expression: 1 ≈ 0.999999
Evaluated: 1 ≈ 0.999999
ERROR: There was an error during testing
Göreli ve mutlak toleransları, ≈
karşılaştırmasından sonra isapprox
fonksiyonunun rtol
ve atol
anahtar argümanlarını ayarlayarak belirtebilirsiniz:
julia> @test 1 ≈ 0.999999 rtol=1e-5
Test Passed
Not edin ki bu, ≈
sembolünün özel bir özelliği değil, daha çok @test
makrosunun genel bir özelliğidir: @test a <op> b key=val
makro tarafından @test op(a, b, key=val)
şeklinde dönüştürülür. Ancak, bu durum ≈
testleri için özellikle faydalıdır.
Test.@inferred
— Macro@inferred [AllowedType] f(x)
Çağrı ifadesinin f(x)
derleyici tarafından çıkarılan aynı türde bir değer döndürdüğünü test eder. Tür kararlılığını kontrol etmek için yararlıdır.
f(x)
herhangi bir çağrı ifadesi olabilir. Türler eşleşirse f(x)
'in sonucunu döndürür ve farklı türler bulursa bir Hata
Sonucu
döndürür.
İsteğe bağlı olarak, AllowedType
testi gevşetir; bu, f(x)
'in türü çıkarılan türle AllowedType
modülünde eşleştiğinde veya dönen tür AllowedType
'in bir alt türü olduğunda geçmesini sağlar. Bu, Union{Nothing, T}
veya Union{Missing, T}
gibi küçük bir birleşim döndüren fonksiyonların tür kararlılığını test ederken yararlıdır.
julia> f(a) = a > 1 ? 1 : 1.0
f (generic function with 1 method)
julia> typeof(f(2))
Int64
julia> @code_warntype f(2)
MethodInstance for f(::Int64)
from f(a) @ Main none:1
Arguments
#self#::Core.Const(f)
a::Int64
Body::UNION{FLOAT64, INT64}
1 ─ %1 = (a > 1)::Bool
└── goto #3 if not %1
2 ─ return 1
3 ─ return 1.0
julia> @inferred f(2)
HATA: dönüş türü Int64 çıkarılan dönüş türü Union{Float64, Int64} ile eşleşmiyor
[...]
julia> @inferred max(1, 2)
2
julia> g(a) = a < 10 ? missing : 1.0
g (generic function with 1 method)
julia> @inferred g(20)
HATA: dönüş türü Float64 çıkarılan dönüş türü Union{Missing, Float64} ile eşleşmiyor
[...]
julia> @inferred Missing g(20)
1.0
julia> h(a) = a < 10 ? missing : f(a)
h (generic function with 1 method)
julia> @inferred Missing h(20)
HATA: dönüş türü Int64 çıkarılan dönüş türü Union{Missing, Float64, Int64} ile eşleşmiyor
[...]
Test.@test_deprecated
— Macro@test_deprecated [pattern] expression
--depwarn=yes
olduğunda, expression
'ın bir deprecasyon uyarısı yaydığını test edin ve expression
'ın değerini döndürün. Log mesajı dizesi, varsayılan olarak r"deprecated"i
olan pattern
ile eşleşecektir.
--depwarn=no
olduğunda, sadece expression
'ın çalıştırılmasının sonucunu döndürün. --depwarn=error
olduğunda, bir ErrorException'ın fırlatıldığını kontrol edin.
Örnekler
# Julia 0.7'de kullanımdan kaldırıldı
@test_deprecated num2hex(1)
# Döndürülen değer, @test ile zincirleme yapılarak test edilebilir:
@test (@test_deprecated num2hex(1)) == "0000000000000001"
Test.@test_warn
— Macro@test_warn msg expr
expr
ifadesinin değerlendirilmesinin msg
dizesini içeren veya msg
düzenli ifadesiyle eşleşen stderr
çıktısına neden olup olmadığını test eder. Eğer msg
bir boolean fonksiyonuysa, msg(output)
ifadesinin true
döndürüp döndürmediğini test eder. Eğer msg
bir demet veya dizi ise, hata çıktısının msg
içindeki her bir öğeyi içerip içermediğini/kapsayıp kapsamadığını kontrol eder. expr
ifadesinin değerlendirilmesinin sonucunu döndürür.
Hata çıktısının yokluğunu kontrol etmek için @test_nowarn
makrosunu da inceleyin.
Not: @warn
ile üretilen uyarılar bu makro ile test edilemez. Bunun yerine @test_logs
kullanın.
Test.@test_nowarn
— Macro@test_nowarn expr
expr
ifadesinin değerlendirilmesinin boş stderr
çıktısı (uyarılar veya diğer mesajlar olmadan) ile sonuçlanıp sonuçlanmadığını test eder. expr
ifadesinin değerlendirilmesinin sonucunu döndürür.
Not: @warn
tarafından üretilen uyarıların yokluğunun bu makro ile test edilemeyeceğini unutmayın. Bunun yerine @test_logs
kullanın.
Broken Tests
Eğer bir test sürekli olarak başarısız oluyorsa, @test_broken
makrosunu kullanacak şekilde değiştirilebilir. Bu, testin başarısız olmaya devam etmesi durumunda testi Broken
olarak işaretler ve test başarılı olursa kullanıcıyı bir Error
ile uyarır.
Test.@test_broken
— Macro@test_broken ex
@test_broken f(args...) key=val ...
Başarılı olması gereken ancak şu anda sürekli olarak başarısız olan bir testi belirtir. ex
ifadesinin false
değerini döndürdüğünü veya bir istisna oluşturduğunu test eder. Eğer öyleyse, bir Broken
Result
döner; aksi takdirde, ifade true
değerini dönerse bir Error
Result
döner. Bu, @test ex broken=true
ile eşdeğerdir.
@test_broken f(args...) key=val...
biçimi, @test
makrosu için olduğu gibi çalışır.
Örnekler
julia> @test_broken 1 == 2
Test Broken
İfade: 1 == 2
julia> @test_broken 1 == 2 atol=0.1
Test Broken
İfade: ==(1, 2, atol = 0.1)
@test_skip
, bir testi değerlendirmeden atlamak için de kullanılabilir, ancak atlanan testi test seti raporlamasında sayar. Test çalışmayacak ancak Broken
Result
verecektir.
Test.@test_skip
— Macro@test_skip ex
@test_skip f(args...) key=val ...
Testin çalıştırılmaması gereken bir testi işaretler, ancak test özeti raporlamasında Broken
olarak dahil edilmelidir. Bu, aralıklı olarak başarısız olan testler veya henüz uygulanmamış işlevselliğin testleri için yararlı olabilir. Bu, @test ex skip=true
ile eşdeğerdir.
@test_skip f(args...) key=val...
biçimi, @test
makrosu için olduğu gibi çalışır.
Örnekler
julia> @test_skip 1 == 2
Test Broken
Skipped: 1 == 2
julia> @test_skip 1 == 2 atol=0.1
Test Broken
Skipped: ==(1, 2, atol = 0.1)
Test result types
Test.Result
— TypeTest.Result
Tüm testler bir sonuç nesnesi üretir. Bu nesne, testin bir test setinin parçası olup olmamasına bağlı olarak saklanabilir veya saklanmayabilir.
Test.Pass
— TypeTest.Pass <: Test.Result
Test koşulu doğruydu, yani ifade doğru olarak değerlendirildi veya doğru istisna fırlatıldı.
Test.Fail
— TypeTest.Fail <: Test.Result
Test koşulu yanlıştı, yani ifade yanlış olarak değerlendirildi veya doğru istisna fırlatılmadı.
Test.Error
— TypeTest.Error <: Test.Result
Test koşulu bir istisna nedeniyle değerlendirilemedi veya Bool
dışında bir şeye değerlendirildi. @test_broken
durumunda, beklenmeyen bir Pass
Result
'ın meydana geldiğini belirtmek için kullanılır.
Test.Broken
— TypeTest.Broken <: Test.Result
Test koşulu, bir kırık testin beklenen (başarısız) sonucudur veya açıkça @test_skip
ile atlanmıştır.
Creating Custom AbstractTestSet
Types
Paketler, record
ve finish
yöntemlerini uygulayarak kendi AbstractTestSet
alt türlerini oluşturabilir. Alt tür, bir açıklama dizesi alan bir tek argümanlı yapıcıya sahip olmalı ve herhangi bir seçenek anahtar kelime argümanları olarak geçirilmelidir.
Test.record
— Functionrecord(ts::AbstractTestSet, res::Result)
Bir sonucu bir test setine kaydedin. Bu işlev, her seferinde bir @test
makrosu tamamlandığında @testset
altyapısı tarafından çağrılır ve test sonucunu (bir Error
olabilir) alır. Ayrıca, test bloğu içinde ancak bir @test
bağlamının dışında bir istisna fırlatıldığında bir Error
ile de çağrılacaktır.
Test.finish
— Functionfinish(ts::AbstractTestSet)
Verilen test seti için gerekli son işlemleri yapar. Bu, bir test bloğu çalıştıktan sonra @testset
altyapısı tarafından çağrılır.
Özel AbstractTestSet
alt türleri, kendilerini test sonuçları ağacına eklemek için ebeveynlerine (varsa) record
çağırmalıdır. Bu şu şekilde uygulanabilir:
if get_testset_depth() != 0
# Bu test setini ebeveyn test setine ekle
parent_ts = get_testset()
record(parent_ts, self)
return self
end
Test
, iç içe geçmiş test setlerinin yürütülmesi sırasında bunları korumaktan sorumludur, ancak herhangi bir sonuç birikimi AbstractTestSet
alt türünün sorumluluğundadır. Bu yığına get_testset
ve get_testset_depth
yöntemleri ile erişebilirsiniz. Bu işlevlerin dışa aktarılmadığını unutmayın.
Test.get_testset
— Functionget_testset()
Görevlerin yerel depolamasından aktif test setini alır. Eğer aktif bir test seti yoksa, yedek varsayılan test setini kullanır.
Test.get_testset_depth
— Functionget_testset_depth()
Varsayılan test seti hariç, aktif test setlerinin sayısını döndürür.
Test
ayrıca iç içe @testset
çağrılarının, açıkça ayarlanmadığı sürece, ebeveynleriyle aynı AbstractTestSet
alt türünü kullandığından emin olur. Test setinin herhangi bir özelliğini yaymaz. Seçenek miras alma davranışı, Test
'in sağladığı yığın altyapısını kullanarak paketler tarafından uygulanabilir.
Temel bir AbstractTestSet
alt türünü tanımlamak şöyle görünebilir:
import Test: Test, record, finish
using Test: AbstractTestSet, Result, Pass, Fail, Error
using Test: get_testset_depth, get_testset
struct CustomTestSet <: Test.AbstractTestSet
description::AbstractString
foo::Int
results::Vector
# constructor takes a description string and options keyword arguments
CustomTestSet(desc; foo=1) = new(desc, foo, [])
end
record(ts::CustomTestSet, child::AbstractTestSet) = push!(ts.results, child)
record(ts::CustomTestSet, res::Result) = push!(ts.results, res)
function finish(ts::CustomTestSet)
# just record if we're not the top-level parent
if get_testset_depth() > 0
record(get_testset(), ts)
return ts
end
# so the results are printed if we are at the top level
Test.print_test_results(ts)
return ts
end
Ve o test set kullanarak şöyle görünüyor:
@testset CustomTestSet foo=4 "custom testset inner 2" begin
# this testset should inherit the type, but not the argument.
@testset "custom testset inner" begin
@test true
end
end
Özel bir test seti kullanmak ve kaydedilen sonuçların herhangi bir dış varsayılan test setinin parçası olarak yazdırılmasını sağlamak için, Test.get_test_counts
tanımlayın. Bu şöyle görünebilir:
using Test: AbstractTestSet, Pass, Fail, Error, Broken, get_test_counts, TestCounts, format_duration
function Test.get_test_counts(ts::CustomTestSet)
passes, fails, errors, broken = 0, 0, 0, 0
# cumulative results
c_passes, c_fails, c_errors, c_broken = 0, 0, 0, 0
for t in ts.results
# count up results
isa(t, Pass) && (passes += 1)
isa(t, Fail) && (fails += 1)
isa(t, Error) && (errors += 1)
isa(t, Broken) && (broken += 1)
# handle children
if isa(t, AbstractTestSet)
tc = get_test_counts(t)::TestCounts
c_passes += tc.passes + tc.cumulative_passes
c_fails += tc.fails + tc.cumulative_fails
c_errors += tc.errors + tc.cumulative_errors
c_broken += tc.broken + tc.cumulative_broken
end
end
# get a duration, if we have one
duration = format_duration(ts)
return TestCounts(true, passes, fails, errors, broken, c_passes, c_fails, c_errors, c_broken, duration)
end
Test.TestCounts
— TypeTestCounts
Test setinin sonuçlarını görüntüleme amaçları için özyinelemeli olarak toplamak için durumu tutar.
Alanlar:
customized
:get_test_counts
fonksiyonunun bu sayım nesnesi için özelleştirilip özelleştirilmediğiAbstractTestSet
. Eğer özel bir yöntem tanımlandıysa, her zaman yapıcıyatrue
geçin.passes
: Geçen@test
çağrılarının sayısı.fails
: Başarısız olan@test
çağrılarının sayısı.errors
: Hata veren@test
çağrılarının sayısı.broken
: Bozuk olan@test
çağrılarının sayısı.passes
: Geçen@test
çağrılarının kümülatif sayısı.fails
: Başarısız olan@test
çağrılarının kümülatif sayısı.errors
: Hata veren@test
çağrılarının kümülatif sayısı.broken
: Bozuk olan@test
çağrılarının kümülatif sayısı.duration
: Söz konusuAbstractTestSet
'in çalıştığı toplam süre, biçimlendirilmiş birString
olarak.
Test.get_test_counts
— Function" gettestcounts(::AbstractTestSet) -> TestCounts
Test setindeki her tür test sonucunun sayısını doğrudan sayan ve alt test setleri arasında toplamını hesaplayan özyinelemeli bir işlevdir.
Özel AbstractTestSet
, toplamlarının DefaultTestSet
ile birlikte sayılması ve görüntülenmesi için bu işlevi uygulamalıdır.
Eğer özel bir TestSet
için bu uygulanmamışsa, yazdırma işlemi başarısızlıklar için x
ve süre için ?s
raporlamaya geri döner."
Test.format_duration
— Functionformat_duration(::AbstractTestSet)
Test set'in çalıştığı süreyi yazdırmak için biçimlendirilmiş bir dize döndürür.
Tanımlı değilse, "?s"
'ye geri döner.
Test.print_test_results
— Functionprint_test_results(ts::AbstractTestSet, depth_pad=0)
Bir AbstractTestSet
'in sonuçlarını biçimlendirilmiş bir tablo olarak yazdırır.
depth_pad
, tüm çıktının önüne ne kadar boşluk eklenmesi gerektiğini belirtir.
Test.finish
içinde çağrılır, eğer finish
edilen test seti en üstteki test setiyse.
Test utilities
Test.GenericArray
— TypeGenericArray
, AbstractArray
arayüzüne program yapan genel dizi API'lerini test etmek için kullanılabilir, böylece işlevlerin standart Array
türü dışında dizi türleriyle çalışabilmesini sağlanır.
Test.GenericDict
— TypeGenericDict
, AbstractDict
arayüzüne program yapan genel dict API'lerini test etmek için kullanılabilir, böylece işlevlerin standart Dict
türü dışında ilişkilendirilmiş türlerle çalışabileceğinden emin olunabilir.
Test.GenericOrder
— TypeGenericOrder
, genel sıralı türlerin desteklenip desteklenmediğini test etmek için kullanılabilir.
Test.GenericSet
— TypeGenericSet
, AbstractSet
arayüzüne program yapan genel küme API'lerini test etmek için kullanılabilir, böylece işlevlerin standart Set
ve BitSet
türleri dışında küme türleriyle çalışabileceğinden emin olunur.
Test.GenericString
— TypeGenericString
, AbstractString
arayüzüne program yapan genel dize API'lerini test etmek için kullanılabilir, böylece işlevlerin standart String
türü dışında dize türleriyle çalışabilmesi sağlanır.
Test.detect_ambiguities
— Functiondetect_ambiguities(mod1, mod2...; recursive=false,
ambiguous_bottom=false,
allowed_undefineds=nothing)
Belirtilen modüllerde tanımlı belirsiz yöntemlerin (Method,Method)
çiftlerinden oluşan bir vektör döndürür. Tüm alt modüllerde test etmek için recursive=true
kullanın.
ambiguous_bottom
, yalnızca Union{}
tür parametreleri tarafından tetiklenen belirsizliklerin dahil edilip edilmeyeceğini kontrol eder; çoğu durumda bunu false
olarak ayarlamak isteyebilirsiniz. Base.isambiguous
için bakın.
allowed_undefineds
ile ilgili bir açıklama için Test.detect_unbound_args
bakın.
allowed_undefineds
, en az Julia 1.8 gerektirir.
Test.detect_unbound_args
— Functiondetect_unbound_args(mod1, mod2...; recursive=false, allowed_undefineds=nothing)
Bağlı olmayan tür parametrelerine sahip olabilecek Method
lerin bir vektörünü döndürür. Tüm alt modüllerde test etmek için recursive=true
kullanın.
Varsayılan olarak, herhangi bir tanımsız sembol bir uyarı tetikler. Bu uyarı, atlanabilecek bir GlobalRef
koleksiyonu sağlayarak bastırılabilir. Örneğin, ayarlamak
allowed_undefineds = Set([GlobalRef(Base, :active_repl),
GlobalRef(Base, :active_repl_backend)])
Base.active_repl
ve Base.active_repl_backend
hakkında uyarıları bastırır.
allowed_undefineds
en az Julia 1.8 gerektirir.
Workflow for Testing Packages
Bize önceki bölümlerde sunulan araçları kullanarak, bir paket oluşturma ve buna test ekleme potansiyel bir iş akışı burada bulunmaktadır.
Generating an Example Package
Bu iş akışı için Example
adında bir paket oluşturacağız:
pkg> generate Example
shell> cd Example
shell> mkdir test
pkg> activate .
Creating Sample Functions
Paketin test edilmesi için bir numaralı gereklilik, test edilecek işlevselliğe sahip olmaktır. Bunun için, test edebileceğimiz bazı basit işlevler ekleyeceğiz. Aşağıdakileri src/Example.jl
dosyasına ekleyin:
module Example
function greet()
"Hello world!"
end
function simple_add(a, b)
a + b
end
function type_multiply(a::Float64, b::Float64)
a * b
end
export greet, simple_add, type_multiply
end
Creating a Test Environment
Example
paketinin kökünden test
dizinine gidin, orada yeni bir ortam etkinleştirin ve Test
paketini ortama ekleyin:
shell> cd test
pkg> activate .
(test) pkg> add Test
Testing Our Package
Artık Example
için testler eklemeye hazırız. Test setlerini çalıştırmak için test
dizininde runtests.jl
adında bir dosya oluşturmak standart bir uygulamadır. O dosyayı test
dizininde oluşturun ve aşağıdaki kodu ekleyin:
using Example
using Test
@testset "Example tests" begin
@testset "Math tests" begin
include("math_tests.jl")
end
@testset "Greeting tests" begin
include("greeting_tests.jl")
end
end
Bu iki dahil edilen dosyayı, math_tests.jl
ve greeting_tests.jl
oluşturmalıyız ve onlara bazı testler eklemeliyiz.
Not:
test
ortamınınProject.toml
dosyasınaExample
eklememiz gerekmediğine dikkat edin. Bu, Julia'nın test sisteminin bir avantajıdır; read about more here şeklinde kullanabilirsiniz.
Writing Tests for math_tests.jl
Test.jl
kullanarak, math_tests.jl
dosyasına ekleyebileceğimiz bazı örnek testler:
@testset "Testset 1" begin
@test 2 == simple_add(1, 1)
@test 3.5 == simple_add(1, 2.5)
@test_throws MethodError simple_add(1, "A")
@test_throws MethodError simple_add(1, 2, 3)
end
@testset "Testset 2" begin
@test 1.0 == type_multiply(1.0, 1.0)
@test isa(type_multiply(2.0, 2.0), Float64)
@test_throws MethodError type_multiply(1, 2.5)
end
Writing Tests for greeting_tests.jl
Test.jl
kullanarak, greeting_tests.jl
dosyasına ekleyebileceğimiz bazı örnek testler:
@testset "Testset 3" begin
@test "Hello world!" == greet()
@test_throws MethodError greet("Antonia")
end
Testing Our Package
Artık testlerimizi ve test
içindeki runtests.jl
scriptimizi eklediğimize göre, Example
paketimizi test etmek için Example
paket ortamının köküne geri dönebilir ve Example
ortamını yeniden etkinleştirebiliriz:
shell> cd ..
pkg> activate .
Oradan, test paketimizi aşağıdaki gibi çalıştırabiliriz:
(Example) pkg> test
Testing Example
Status `/tmp/jl_Yngpvy/Project.toml`
[fa318bd2] Example v0.1.0 `/home/src/Projects/tmp/errata/Example`
[8dfed614] Test `@stdlib/Test`
Status `/tmp/jl_Yngpvy/Manifest.toml`
[fa318bd2] Example v0.1.0 `/home/src/Projects/tmp/errata/Example`
[2a0f44e3] Base64 `@stdlib/Base64`
[b77e0a4c] InteractiveUtils `@stdlib/InteractiveUtils`
[56ddb016] Logging `@stdlib/Logging`
[d6f4376e] Markdown `@stdlib/Markdown`
[9a3f8284] Random `@stdlib/Random`
[ea8e919c] SHA `@stdlib/SHA`
[9e88b42a] Serialization `@stdlib/Serialization`
[8dfed614] Test `@stdlib/Test`
Testing Running tests...
Test Summary: | Pass Total
Example tests | 9 9
Testing Example tests passed
Ve ve her şey doğru giderse, yukarıda benzer bir çıktı görmelisiniz. Test.jl
kullanarak, paketler için daha karmaşık testler eklenebilir, ancak bu, geliştiricileri kendi oluşturdukları paketleri test etmeye başlama konusunda yönlendirmelidir.
Code Coverage
Testler sırasında kod kapsamı takibi, pkg> test --coverage
bayrağını kullanarak (veya daha düşük bir seviyede --code-coverage
julia argümanını kullanarak) etkinleştirilebilir. Bu, julia-runtest GitHub eyleminde varsayılan olarak açıktır.
Kapsama değerlendirmek için ya yerel olarak kaynak dosyaların yanında oluşturulan .cov
dosyalarını manuel olarak inceleyin ya da CI'de julia-processcoverage GitHub eylemini kullanın.
Julia 1.11'den itibaren, kapsama paket ön derleme aşamasında toplanmamaktadır.