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=trueex 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çtiBu, 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==trueolduğunda geçmesi gereken ancak şu anda sürekli olarak başarısız olan bir testi belirtir.exifadesininfalsedeğerine eşit olduğunu veya bir istisna oluşturduğunu test eder. Eğer öyleyseBrokenResultdöndürür veya ifadetruedeğerine eşit olursaErrorResultdöndürür.cond==falseolduğunda normal@test exdeğerlendirilir.skip=cond,cond==trueolduğunda çalıştırılmaması gereken ancak test özeti raporlamasındaBrokenolarak 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==falseolduğunda normal@test exdeğ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çtibroken ve skip anahtar argümanları en az Julia 1.7 gerektirir.
Test.@test_throws — Macro@test_throws exception exprexpr 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 PassedEğ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 testingEğ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 testingEğ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: MethodErrorWorking 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; endbegin/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:trueise, iç içe test setlerinin sonuç özeti, hepsi geçtiğinde bile gösterilir (varsayılanfalse).showtiming:trueise, her gösterilen test setinin süresi gösterilir (varsayılantrue).failfast:trueise, 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_FAILFASTortam 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ştuTest.TestSetException — TypeTestSetExceptionBir 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.0sTest 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.0sFonksiyonları ç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.0sBu, 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.0sEğ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] ifadeifade 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
endInfo 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)) == 42Uyarı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 PassedTest.LogRecord — TypeLogRecordTek bir günlük olayının sonuçlarını saklar. Alanlar:
level: günlük mesajınınLogLevelseviyesimessage: 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 testingGö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 PassedNot 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 exprexpr 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 exprexpr 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.ResultTü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.ResultTest koşulu doğruydu, yani ifade doğru olarak değerlendirildi veya doğru istisna fırlatıldı.
Test.Fail — TypeTest.Fail <: Test.ResultTest koşulu yanlıştı, yani ifade yanlış olarak değerlendirildi veya doğru istisna fırlatılmadı.
Test.Error — TypeTest.Error <: Test.ResultTest 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.ResultTest 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
endTest, 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
endVe 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)
endTest.TestCounts — TypeTestCountsTest setinin sonuçlarını görüntüleme amaçları için özyinelemeli olarak toplamak için durumu tutar.
Alanlar:
customized:get_test_countsfonksiyonunun bu sayım nesnesi için özelleştirilip özelleştirilmediğiAbstractTestSet. Eğer özel bir yöntem tanımlandıysa, her zaman yapıcıyatruegeç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ş birStringolarak.
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 Methodlerin 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
endCreating 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 TestTesting 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
endBu iki dahil edilen dosyayı, math_tests.jl ve greeting_tests.jl oluşturmalıyız ve onlara bazı testler eklemeliyiz.
Not:
testortamınınProject.tomldosyasınaExampleeklememiz 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)
endWriting 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")
endTesting 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 passedVe 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.