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.runtestsFunction
Base.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.

source

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.@testMacro
@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 ifadesinin false değerine eşit olduğunu veya bir istisna oluşturduğunu test eder. Eğer öyleyse Broken Result döndürür veya ifade true değerine eşit olursa Error 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ında Broken 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
Julia 1.7

broken ve skip anahtar argümanları en az Julia 1.7 gerektirir.

source
Test.@test_throwsMacro
@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.

Julia 1.8

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)
source

Ö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.

Note

@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.@testsetMacro
@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ılan false).
  • showtiming: true ise, her gösterilen test setinin süresi gösterilir (varsayılan true).
  • failfast: true ise, herhangi bir test hatası veya hatası, test setinin ve herhangi bir alt test setinin hemen dönmesine neden olur (varsayılan false). Bu, ayrıca JULIA_TEST_FAILFAST ortam değişkeni aracılığıyla küresel olarak ayarlanabilir.
Julia 1.8

@testset test_func() en az Julia 1.8 gerektirir.

Julia 1.9

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).

Julia 1.9

@testset let en az Julia 1.9 gerektirir.

Julia 1.10

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
source

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_logsMacro
@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. ```

source
Test.TestLoggerType
TestLogger(; 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
source
Test.LogRecordType
LogRecord

Tek bir günlük olayının sonuçlarını saklar. Alanlar:

  • level: günlük mesajının LogLevel seviyesi
  • message: 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ği
  • file: günlük olayını içeren dosya
  • line: 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ı
source

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.@inferredMacro
@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
[...]
source
Test.@test_deprecatedMacro
@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"
source
Test.@test_warnMacro
@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.

source
Test.@test_nowarnMacro
@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.

source

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_brokenMacro
@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)
source

@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_skipMacro
@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)
source

Test result types

Test.ResultType
Test.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.

source
Test.PassType
Test.Pass <: Test.Result

Test koşulu doğruydu, yani ifade doğru olarak değerlendirildi veya doğru istisna fırlatıldı.

source
Test.FailType
Test.Fail <: Test.Result

Test koşulu yanlıştı, yani ifade yanlış olarak değerlendirildi veya doğru istisna fırlatılmadı.

source
Test.ErrorType
Test.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.

source
Test.BrokenType
Test.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.

source

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.recordFunction
record(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.

source
Test.finishFunction
finish(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
source

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_testsetFunction
get_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.

source

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.TestCountsType
TestCounts

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ği AbstractTestSet. Eğer özel bir yöntem tanımlandıysa, her zaman yapıcıya true 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 konusu AbstractTestSet'in çalıştığı toplam süre, biçimlendirilmiş bir String olarak.
source
Test.get_test_countsFunction

" 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."

source
Test.format_durationFunction
format_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.

source
Test.print_test_resultsFunction
print_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.

source

Test utilities

Test.GenericArrayType

GenericArray, 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.

source
Test.GenericDictType

GenericDict, 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.

source
Test.GenericOrderType

GenericOrder, genel sıralı türlerin desteklenip desteklenmediğini test etmek için kullanılabilir.

source
Test.GenericSetType

GenericSet, 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.

source
Test.GenericStringType

GenericString, 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.

source
Test.detect_ambiguitiesFunction
detect_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.

Julia 1.8

allowed_undefineds, en az Julia 1.8 gerektirir.

source
Test.detect_unbound_argsFunction
detect_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.

Julia 1.8

allowed_undefineds en az Julia 1.8 gerektirir.

source

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ın Project.toml dosyasına Example 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

Julia 1.11'den itibaren, kapsama paket ön derleme aşamasında toplanmamaktadır.