Julia 1.0 - Unit Testing

इकाई का परीक्षण




julia

इकाई का परीक्षण

परीक्षण बेस जूलिया

जूलिया तेजी से विकास के अधीन है और कई प्लेटफार्मों में कार्यक्षमता को सत्यापित करने के लिए एक व्यापक परीक्षण सूट है। यदि आप स्रोत से जूलिया का निर्माण करते हैं, तो आप इस टेस्ट सूट को make test साथ चला सकते हैं। एक बाइनरी इंस्टॉल में, आप Base.runtests() का उपयोग करके टेस्ट सूट चला सकते हैं।

Base.runtests फ़ंक्शन

Base.runtests(tests=["all"]; ncores=ceil(Int, Sys.CPU_THREADS / 2),
              exit_on_error=false, [seed])

परीक्षणों में सूचीबद्ध जूलिया यूनिट परीक्षण चलाएं, जो ncores प्रोसेसर का उपयोग करके या तो एक स्ट्रिंग या स्ट्रिंग की एक सरणी हो ncores है। यदि बाहर exit_on_error false , जब एक परीक्षण विफल हो जाता है, तो अन्य फ़ाइलों में शेष सभी परीक्षण अभी भी चलाए जाएंगे; वे अन्यथा खारिज कर दिए जाते हैं, जब बाहर exit_on_error == true । यदि कीवर्ड तर्क के माध्यम से एक बीज प्रदान किया जाता है, तो इसका उपयोग वैश्विक आरएनजी को उस संदर्भ में बीजने के लिए किया जाता है जहां परीक्षण चलाए जाते हैं; अन्यथा बीज को अनियमित रूप से चुना जाता है।

source

बेसिक यूनिट टेस्ट

Test मॉड्यूल सरल इकाई परीक्षण कार्यक्षमता प्रदान करता है। यूनिट परीक्षण यह देखने का एक तरीका है कि क्या यह जाँचने से आपका कोड सही है कि परिणाम आपके द्वारा अपेक्षित हैं। यह सुनिश्चित करने में मददगार हो सकता है कि परिवर्तन करने के बाद भी आपका कोड काम करता रहे, और इसका उपयोग तब किया जा सकता है जब आपके कोड के पूर्ण होने पर व्यवहार को निर्दिष्ट करने के तरीके के रूप में विकसित किया जा रहा हो।

सरल इकाई परीक्षण @test और @test_throws मैक्रोज़ के साथ किया जा सकता है:

[email protected] मैक्रो

@test ex
@test f(args...) key=val ...

टेस्ट जो एक्सप्रेशन ex का true मूल्यांकन करता true । यदि यह false , तो एक Fail Result लौटाता है, यदि यह false , तो एक Fail Result और इसका मूल्यांकन नहीं किया जा सकता है।

उदाहरण

julia> @test true
Test Passed

julia> @test [1, 2] + [2, 1] == [3, 3]
Test Passed

@test f(args...) key=val... फॉर्म @test f(args..., key=val...) लिखने के बराबर है जो तब उपयोगी हो सकता है जब एक्सप्रेशन सिंटैक्स का उपयोग कर कॉल हो। अनुमानित तुलनाओं जैसे:

julia> @test π ≈ 3.14 atol=0.01
Test Passed

यह @test ≈(π, 3.14, atol=0.01) परीक्षण @test ≈(π, 3.14, atol=0.01) । यह एक से अधिक अभिव्यक्ति की आपूर्ति करने में त्रुटि है जब तक कि पहली कॉल अभिव्यक्ति नहीं है और बाकी असाइनमेंट ( k=v ) हैं।

source

[email protected]_throws मैक्रो

@test_throws exception expr

परीक्षण जो एक्सप्रेशन expr है वह exception । अपवाद या तो एक प्रकार, या एक मूल्य निर्दिष्ट कर सकता है (जिसे खेतों की तुलना करके समानता के लिए परीक्षण किया जाएगा)। ध्यान दें कि @test_throws एक अनुगामी कीवर्ड फ़ॉर्म का समर्थन नहीं करता है।

उदाहरण

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
source

उदाहरण के लिए, मान लें कि हम अपने नए फ़ंक्शन foo(x) अपेक्षा के अनुसार काम करना चाहते हैं:

julia> using Test

julia> foo(x) = length(x)^2
foo (generic function with 1 method)

यदि शर्त सही है, तो एक Pass लौटा दिया जाता है:

julia> @test foo("bar") == 9
Test Passed

julia> @test foo("fizz") >= 10
Test Passed

यदि स्थिति झूठी है, तो एक Fail लौटा दी जाती है और एक अपवाद फेंक दिया जाता है:

julia> @test foo("f") == 20
Test Failed at none:1
  Expression: foo("f") == 20
   Evaluated: 1 == 20
ERROR: There was an error during testing

यदि स्थिति का मूल्यांकन नहीं किया जा सकता है क्योंकि एक अपवाद फेंक दिया गया था, जो इस मामले में होता है क्योंकि length प्रतीकों के लिए परिभाषित नहीं होती है, एक Error वस्तु वापस आ जाती है और एक अपवाद फेंक दिया जाता है:

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

यदि हम उम्मीद करते हैं कि अभिव्यक्ति का मूल्यांकन अपवाद छोड़ देना चाहिए , तो हम @test_throws का उपयोग @test_throws देख सकते हैं कि ऐसा होता है:

julia> @test_throws MethodError foo(:cat)
Test Passed
      Thrown: MethodError

टेस्ट सेट के साथ काम करना

आमतौर पर बड़ी संख्या में परीक्षणों का उपयोग यह सुनिश्चित करने के लिए किया जाता है कि इनपुट की एक सीमा से अधिक कार्य सही ढंग से काम करते हैं। घटना में एक परीक्षण विफल हो जाता है, डिफ़ॉल्ट व्यवहार तुरंत एक अपवाद फेंकना है। हालांकि, आमतौर पर बाकी परीक्षणों को चलाने के लिए बेहतर होता है कि एक बेहतर चित्र प्राप्त करने के लिए कोड में कितनी त्रुटियों का परीक्षण किया जा रहा है।

@testset मैक्रो का उपयोग समूह परीक्षणों में सेट में किया जा सकता है। एक परीक्षण सेट में सभी परीक्षण चलाए जाएंगे, और परीक्षण सेट के अंत में एक सारांश मुद्रित किया जाएगा। यदि कोई भी परीक्षण विफल हो गया, या किसी त्रुटि के कारण मूल्यांकन नहीं किया जा सका, तो परीक्षण सेट फिर TestSetException फेंक TestSetException

[email protected] Macro

@testset [CustomTestSet] [option=val  ...] ["description"] begin ... end
@testset [CustomTestSet] [option=val  ...] ["description $v"] for v in (...) ... end
@testset [CustomTestSet] [option=val  ...] ["description $v, $w"] for v in (...), w in (...) ... end

यदि लूप प्रदान किया जाता है तो एक नया परीक्षण सेट, या कई परीक्षण सेट शुरू करता है।

यदि कोई कस्टम टेस्टसेट प्रकार नहीं दिया जाता है तो यह डिफॉल्टटसेट बनाने में चूक करता है। DefaultTestSet सभी DefaultTestSet रिकॉर्ड करता है और, यदि कोई भी Fail s या Error s हैं, तो टेस्ट परिणामों के सारांश के साथ टॉप-लेवल (नॉन-नेस्टेड) ​​टेस्ट सेट के अंत में एक अपवाद फेंकता है।

कोई भी कस्टम टेस्टसेट टाइप ( AbstractTestSet उपप्रकार) दिया जा सकता है और यह किसी भी नेस्टेड @testset इनवोकेशन के लिए भी उपयोग किया जाएगा। दिए गए विकल्प केवल परीक्षण सेट पर लागू होते हैं जहां उन्हें दिया जाता है। डिफ़ॉल्ट परीक्षण सेट प्रकार कोई विकल्प नहीं लेता है।

विवरण स्ट्रिंग लूप सूचकांकों से प्रक्षेप को स्वीकार करता है। यदि कोई विवरण नहीं दिया गया है, तो एक का निर्माण चर के आधार पर किया जाता है।

डिफ़ॉल्ट रूप से @testset मैक्रो टेस्टसेट ऑब्जेक्ट को स्वयं वापस कर देगा, हालांकि यह व्यवहार अन्य टेस्टसेट प्रकारों में अनुकूलित किया जा सकता है। यदि एक लूप का उपयोग किया जाता है, तो मैक्रो इकट्ठा करता है और finish विधि के रिटर्न मानों की एक सूची देता है, जो डिफ़ॉल्ट रूप से प्रत्येक पुनरावृत्ति में उपयोग किए जाने वाले टेस्टसेट ऑब्जेक्ट्स की एक सूची लौटाएगा।

@testset के शरीर के निष्पादन से पहले, Random.seed!(seed) लिए एक अंतर्निहित कॉल है जहां seed वैश्विक Random.seed!(seed) का वर्तमान बीज है। इसके अलावा, निकाय के निष्पादन के बाद, वैश्विक @testset की @testset बहाल हो जाती है, जो @testset से पहले थी। यह विफलता के मामले में प्रतिलिपि प्रस्तुत करने @testset को कम करने और वैश्विक @testset राज्य पर उनके दुष्प्रभावों की परवाह किए बिना @testset की निर्बाध पुन: व्यवस्था की अनुमति देने के लिए है।

उदाहरण

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
trigonometric identities |    4      4
source

हम एक परीक्षण सेट में foo(x) फ़ंक्शन के लिए अपने परीक्षण रख सकते हैं:

julia> @testset "Foo Tests" begin
           @test foo("a")   == 1
           @test foo("ab")  == 4
           @test foo("abc") == 9
       end;
Test Summary: | Pass  Total
Foo Tests     |    3      3

टेस्ट सेट को भी नेस्टेड किया जा सकता है:

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
Foo Tests     |    8      8

इस घटना में कि एक नेस्टेड परीक्षण सेट में कोई विफलता नहीं है, जैसा कि यहां हुआ, यह सारांश में छिपा होगा। यदि हमारे पास परीक्षण विफलता है, तो केवल असफल परीक्षण सेट के लिए विवरण दिखाया जाएगा:

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
Foo Tests     |    3     1      4
  Animals     |    2            2
  Arrays      |    1     1      2
ERROR: Some tests did not pass: 3 passed, 1 failed, 0 errored, 0 broken.

अन्य टेस्ट मैक्रों

चूंकि फ्लोटिंग-पॉइंट वैल्यू पर गणना @test a ≈ b हो सकती है, आप @test a ≈ b (जहाँ , टैब के पूरा होने के माध्यम से टाइप किया जाता है, isapprox फ़ंक्शन है) का उपयोग करके लगभग समता जाँच कर सकते हैं या सीधे isapprox उपयोग कर isapprox हैं।

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

[email protected] मैक्रो

@inferred f(x)

परीक्षण जो कॉल एक्सप्रेशन f(x) कंपाइलर द्वारा अनुमानित उसी प्रकार का मान देता है। यह स्थिरता के लिए जाँच करने के लिए उपयोगी है।

f(x) कोई भी कॉल एक्सप्रेशन हो सकता है। यदि प्रकार से मेल खाता है, तो f(x) का परिणाम लौटाता है और यदि विभिन्न प्रकार के मिलते हैं तो एक Error Result

julia> f(a, b, c) = b > 1 ? 1 : 1.0
f (generic function with 1 method)

julia> typeof(f(1, 2, 3))
Int64

julia> @code_warntype f(1, 2, 3)
Body::UNION{FLOAT64, INT64}
1 1 ─ %1 = (Base.slt_int)(1, b)::Bool
  └──      goto #3 if not %1
  2 ─      return 1
  3 ─      return 1.0

julia> @inferred f(1, 2, 3)
ERROR: return type Int64 does not match inferred return type Union{Float64, Int64}
Stacktrace:
[...]

julia> @inferred max(1, 2)
2
source

[email protected]_logs मैक्रो

@test_logs [log_patterns...] [keywords] expression

collect_test_logs का उपयोग करके expression द्वारा उत्पन्न लॉग रिकॉर्ड की एक सूची एकत्र करें, जांचें कि वे अनुक्रम log_patterns मेल खाते हैं, और expression का मूल्य वापस करते हैं। keywords लॉग रिकॉर्ड के कुछ सरल फ़िल्टरिंग प्रदान करते हैं: min_level कीवर्ड न्यूनतम लॉग स्तर को नियंत्रित करता है जो परीक्षण के लिए एकत्र किया जाएगा, match_mode कीवर्ड यह परिभाषित करता है कि मिलान कैसे किया जाएगा (डिफ़ॉल्ट :all चेक और पैटर्न match_mode साथ मेल खाते हैं; :any यह जांचने के लिए कि पैटर्न कम से कम एक बार अनुक्रम में कहीं मेल खाता है।)

सबसे उपयोगी लॉग पैटर्न फॉर्म (level,message) का एक सरल टपल है। अन्य लॉग मेटाडेटा से मेल खाने के लिए टपल तत्वों की एक अलग संख्या का उपयोग किया जा सकता है, जो handle_message फंक्शन के माध्यम से handle_message को पास करने के लिए तर्कों के अनुरूप है: (level,message,module,group,id,file,line) । जो तत्व मौजूद हैं उन्हें लॉग रिकॉर्ड फ़ील्ड के साथ डिफ़ॉल्ट रूप से == का उपयोग करके जोड़े के साथ मेल किया जाएगा, विशेष मामलों के साथ कि मानक लॉग स्तरों के लिए Symbol उपयोग किया जा सकता है, और Regex में occursin स्ट्रिंग का उपयोग occursin या सिंबल फ़ील्ड से मेल occursin

उदाहरण

एक फ़ंक्शन पर विचार करें जो एक चेतावनी और कई डिबग संदेशों को लॉग करता है:

function foo(n)
    @info "Doing foo with n=$n"
    for i=1:n
        @debug "Iteration $i"
    end
    42
end

हम जानकारी संदेश का उपयोग करके परीक्षण कर सकते हैं

@test_logs (:info,"Doing foo with n=2") foo(2)

यदि हम डिबग संदेशों का परीक्षण भी करना चाहते हैं, तो इन्हें min_level कीवर्ड के साथ सक्षम करने की आवश्यकता है:

@test_logs (:info,"Doing foo with n=2") (:debug,"Iteration 1") (:debug,"Iteration 2") min_level=Debug foo(2)

मैक्रो को @test साथ जंजीर दी जा सकती है ताकि लौटे हुए मूल्य का भी परीक्षण किया जा सके:

@test (@test_logs (:info,"Doing foo with n=2") foo(2)) == 42
source

[email protected]_deprecated मैक्रो

@test_deprecated [pattern] expression

जब --depwarn=yes , परीक्षण करें कि expression एक --depwarn=yes चेतावनी का उत्सर्जन करती है और expression का मूल्य वापस करती है। लॉग संदेश स्ट्रिंग को pattern विरुद्ध मिलान किया जाएगा जो कि r"deprecated"i लिए चूक है।

जब --depwarn=no , बस निष्पादित expression का परिणाम लौटाते हैं। जब --depwarn=error , जाँचें कि एक ErrorException फेंक दिया गया है।

उदाहरण

# Deprecated in julia 0.7
@test_deprecated num2hex(1)

# The returned value can be tested by chaining with @test:
@test (@test_deprecated num2hex(1)) == "0000000000000001"
source

[email protected]_warn मैक्रो

@test_warn msg expr

परीक्षण करें कि क्या मूल्यांकन स्ट्रिंग परिणाम में msg स्ट्रिंग शामिल है या msg नियमित अभिव्यक्ति से मेल खाता है। यदि msg एक बूलियन फ़ंक्शन है, तो परीक्षण करता है कि क्या msg(output) true । यदि msg एक tuple या array है, तो चेक करें कि त्रुटि आउटपुट में msg में प्रत्येक आइटम से मेल खाता है / मेल खाता है। expr मूल्यांकन का परिणाम देता है।

त्रुटि आउटपुट की अनुपस्थिति के लिए जाँच करने के लिए @test_nowarn भी देखें।

source

[email protected]_nowarn मैक्रो

@test_nowarn expr

परीक्षण करें कि खाली stderr आउटपुट (कोई चेतावनी या अन्य संदेश) में expr परिणामों का मूल्यांकन करना है या नहीं। expr मूल्यांकन का परिणाम देता है।

source

टूटे हुए टेस्ट

यदि कोई परीक्षण लगातार विफल रहता है तो इसे @test_broken मैक्रो का उपयोग करने के लिए बदला जा सकता है। यदि परीक्षण विफल हो जाता है और परीक्षण के सफल होने पर उपयोगकर्ता को एक Error माध्यम से सचेत करता है तो यह Broken रूप में परीक्षण को निरूपित करेगा।

[email protected]_broken मैक्रो

@test_broken ex
@test_broken f(args...) key=val ...

एक परीक्षण का संकेत देता है जो पास होना चाहिए लेकिन वर्तमान में लगातार विफल रहता है। परीक्षण जो अभिव्यक्ति ex मूल्यांकन करता है वह false या अपवाद का कारण बनता है। Broken Result लौटाता है अगर यह करता है, या एक Error Result अगर एक्सप्रेशन true

@test_broken f(args...) key=val... फ़ॉर्म @test मैक्रो के लिए कार्य करता है।

उदाहरण

julia> @test_broken 1 == 2
Test Broken
  Expression: 1 == 2

julia> @test_broken 1 == 2 atol=0.1
Test Broken
  Expression: ==(1, 2, atol=0.1)
source

@test_skip बिना मूल्यांकन के परीक्षण छोड़ने के लिए भी उपलब्ध है, लेकिन परीक्षण सेट रिपोर्टिंग में स्किप किए गए परीक्षण की गिनती कर रहा है। टेस्ट नहीं चलेगा लेकिन Broken Result देता है।

[email protected]_skip मैक्रो

@test_skip ex
@test_skip f(args...) key=val ...

एक ऐसे परीक्षण को चिह्नित करता है जिसे निष्पादित नहीं किया जाना चाहिए लेकिन Broken रूप में टेस्ट सारांश रिपोर्टिंग में शामिल किया जाना चाहिए। यह उन परीक्षणों के लिए उपयोगी हो सकता है जो रुक-रुक कर विफल हो जाते हैं, या अभी तक लागू नहीं किए गए कार्यक्षमता के परीक्षण।

@test_skip f(args...) key=val... फ़ॉर्म @test मैक्रो के लिए कार्य करता है।

उदाहरण

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

कस्टम AbstractTestSet प्रकार बनाना

पैकेज record और finish विधियों को लागू करके अपना खुद का AbstractTestSet उपप्रकार बना सकते हैं। उपप्रकार में एक-एक तर्क निर्माता होना चाहिए जो विवरण स्ट्रिंग ले रहा हो, जिसमें कीवर्ड तर्क के रूप में कोई विकल्प पारित हो।

Test.record फंक्शन

record(ts::AbstractTestSet, res::Result)

किसी परिणाम के लिए रिकॉर्ड करें। इस फ़ंक्शन को @testset इन्फ्रास्ट्रक्चर द्वारा बुलाया जाता है, @testset हर बार @test मैक्रो पूरा होता है, और इसे परीक्षा परिणाम (जो एक Error हो सकती है) दिया जाता है। यह भी एक Error साथ कहा जाएगा यदि एक अपवाद परीक्षण ब्लॉक के अंदर फेंक दिया जाता है, लेकिन एक @test संदर्भ के बाहर।

source

Test.finish फंक्शन

finish(ts::AbstractTestSet)

दिए गए परीक्षण के लिए आवश्यक कोई अंतिम प्रसंस्करण करें। टेस्ट ब्लॉक निष्पादित होने के बाद @testset बुनियादी ढांचे द्वारा इसे बुलाया जाता है। इस फ़ंक्शन के लिए एक सामान्य उपयोग, get_testset का उपयोग करके, माता-पिता की परिणाम सूची में टेस्टसेट रिकॉर्ड करना है।

source

Test नेस्टेड टेस्टसेट के स्टैक को बनाए रखने की ज़िम्मेदारी लेता है क्योंकि इन्हें निष्पादित किया जाता है, लेकिन किसी भी परिणाम संचय के लिए AbstractTestSet उपप्रकार की ज़िम्मेदारी है। आप इस स्टैक को get_testset और get_testset_depth तरीकों से एक्सेस कर सकते हैं। ध्यान दें कि ये फ़ंक्शन निर्यात नहीं किए गए हैं।

Test.get_testset फ़ंक्शन

get_testset()

कार्य के स्थानीय संग्रहण से सक्रिय परीक्षण सेट प्राप्त करें। यदि कोई परीक्षण सेट सक्रिय नहीं है, तो फ़ॉलबैक डिफ़ॉल्ट परीक्षण सेट का उपयोग करें।

source

Test.get_testset_depth फ़ंक्शन

get_testset_depth()

सक्रिय परीक्षण सेटों की संख्या लौटाता है, डिफ़ॉल्ट परीक्षण सेट सहित नहीं

source

Test यह भी सुनिश्चित करता है कि नेस्टेड @testset उनके मूल के रूप में एक ही AbstractTestSet उपप्रकार का उपयोग करता है जब तक कि यह स्पष्ट रूप से सेट न हो। यह परीक्षणकर्ता के किसी भी गुण का प्रचार नहीं करता है। विकल्प वंशानुक्रम व्यवहार को स्टैक अवसंरचना का उपयोग करके पैकेज द्वारा कार्यान्वित किया जा सकता है जो Test प्रदान करता है।

एक मूल AbstractTestSet उपप्रकार को परिभाषित करना इस तरह दिख सकता है:

import 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)
    end
    ts
end

और उस टेस्टसेट का उपयोग करके ऐसा दिखता है:

@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