Sök…


Syntax

  • @ test [expr]
  • @test_throws [Undantag] [expr]
  • @testset "[namn]" börjar; [tester]; slutet
  • Pkg.test ([paket])

Anmärkningar

Standardbiblioteksdokumentationen för Base.Test täcker ytterligare material utöver vad som visas i dessa exempel.

Testa ett paket

För att köra enhetstesterna för ett paket använder Pkg.test funktionen Pkg.test . För ett paket som heter MyPackage skulle kommandot vara

julia> Pkg.test("MyPackage")

En förväntad produktion skulle likna

INFO: Computing test dependencies for MyPackage...
INFO: Installing BaseTestNext v0.2.2
INFO: Testing MyPackage
Test Summary: | Pass  Total
  Data        |   66     66
Test Summary: | Pass  Total
  Monetary    |  107    107
Test Summary: | Pass  Total
  Basket      |   47     47
Test Summary: | Pass  Total
  Mixed       |   13     13
Test Summary: | Pass  Total
  Data Access |   35     35
INFO: MyPackage tests passed
INFO: Removing BaseTestNext v0.2.2

men uppenbarligen kan man inte förvänta sig att det matchar ovanstående exakt, eftersom olika paket använder olika ramverk.

Detta kommando kör paketets test/runtests.jl fil i en ren miljö.

Man kan testa alla installerade paket samtidigt med

julia> Pkg.test()

men det tar vanligtvis mycket lång tid.

Att skriva ett enkelt test

Enhetstester deklareras i test/runtests.jl filen i ett paket. Vanligtvis börjar den här filen

using MyModule
using Base.Test

Den grundläggande @test är @test . Detta makro är som ett påstående av olika slag. Alla booleska uttryck kan testas i @test test- @test :

@test 1 + 1 == 2
@test iseven(10)
@test 9 < 10 || 10 < 9

Vi kan testa @test i REPL:

julia> using Base.Test

julia> @test 1 + 1 == 2
Test Passed
  Expression: 1 + 1 == 2
   Evaluated: 2 == 2

julia> @test 1 + 1 == 3
Test Failed
  Expression: 1 + 1 == 3
   Evaluated: 2 == 3
ERROR: There was an error during testing
 in record(::Base.Test.FallbackTestSet, ::Base.Test.Fail) at ./test.jl:397
 in do_test(::Base.Test.Returned, ::Expr) at ./test.jl:281

Testmakroet kan användas på nästan var som helst, till exempel i slingor eller funktioner:

# For positive integers, a number's square is at least as large as the number
for i in 1:10
    @test i^2 ≥ i
end

# Test that no two of a, b, or c share a prime factor
function check_pairwise_coprime(a, b, c)
    @test gcd(a, b) == 1
    @test gcd(a, c) == 1
    @test gcd(b, c) == 1
end

check_pairwise_coprime(10, 23, 119)

Skriva en testuppsättning

0.5.0

I version v0.5 är testuppsättningar inbyggda i standardbiblioteket Base.Test modulen, och du behöver inte göra något speciellt (förutom att using Base.Test ) för att använda dem.

0.4.0

Testuppsättningar ingår inte i Julia v0.4: s Base.Test bibliotek. Istället måste du REQUIRE BaseTestNext modulen och lägga till using BaseTestNext till din fil. För att stödja både version 0.4 och 0.5 kan du använda

if VERSION ≥ v"0.5.0-dev+7720"
    using Base.Test
else
    using BaseTestNext
    const Test = BaseTestNext
end

Det är bra att gruppera relaterade @test tillsammans i en testuppsättning. Förutom tydligare testorganisation erbjuder testuppsättningar bättre output och mer anpassningsbarhet.

För att definiera en testuppsättning ska du helt enkelt slå in valfritt antal @test med ett @testset block:

@testset "+" begin
    @test 1 + 1 == 2
    @test 2 + 2 == 4
end

@testset "*" begin
    @test 1 * 1 == 1
    @test 2 * 2 == 4
end

Att köra dessa testuppsättningar skriver ut följande utgång:

Test Summary: | Pass  Total
  +           |    2      2

Test Summary: | Pass  Total
  *           |    2      2

Även om en testuppsättning innehåller ett misslyckande test, kommer hela testuppsättningen att köras till slut, och felen kommer att registreras och rapporteras:

@testset "-" begin
    @test 1 - 1 == 0
    @test 2 - 2 == 1
    @test 3 - () == 3
    @test 4 - 4 == 0
end

Att köra denna testuppsättning resulterar i

-: Test Failed
  Expression: 2 - 2 == 1
   Evaluated: 0 == 1
 in record(::Base.Test.DefaultTestSet, ::Base.Test.Fail) at ./test.jl:428
    ...
-: Error During Test
  Test threw an exception of type MethodError
  Expression: 3 - () == 3
  MethodError: no method matching -(::Int64, ::Tuple{})
    ...
Test Summary: | Pass  Fail  Error  Total
  -           |    2     1      1      4
ERROR: Some tests did not pass: 2 passed, 1 failed, 1 errored, 0 broken.
    ...

Testuppsättningar kan kapslas, vilket möjliggör godtycklig djup organisation

@testset "Int" begin
    @testset "+" begin
        @test 1 + 1 == 2
        @test 2 + 2 == 4
    end
    @testset "-" begin
        @test 1 - 1 == 0
    end
end

Om testen klarar visar detta bara resultaten för den yttersta testuppsättningen:

Test Summary: | Pass  Total
  Int         |    3      3

Men om testen misslyckas rapporteras en nedläggning i den exakta testuppsättningen och testet som orsakar felet.

@testset kan användas med en for loop för att skapa många testuppsättningar samtidigt:

@testset for i in 1:5
    @test 2i == i + i
    @test i^2 == i * i
    @test i ÷ i == 1
end

som rapporterar

Test Summary: | Pass  Total
  i = 1       |    3      3
Test Summary: | Pass  Total
  i = 2       |    3      3
Test Summary: | Pass  Total
  i = 3       |    3      3
Test Summary: | Pass  Total
  i = 4       |    3      3
Test Summary: | Pass  Total
  i = 5       |    3      3

En gemensam struktur är att ha yttre testuppsättningar testkomponenter eller typer. Inom dessa yttre testuppsättningar anger inre testtestbeteende. Anta till exempel att vi skapade en typ UniversalSet med en singleton-instans som innehåller allt. Innan vi ens implementerar typen kan vi använda testdrivna utvecklingsprinciper och implementera testerna:

@testset "UniversalSet" begin
    U = UniversalSet.instance
    @testset "egal/equal" begin
        @test U === U
        @test U == U
    end

    @testset "in" begin
        @test 1 in U
        @test "Hello World" in U
        @test Int in U
        @test U in U
    end

    @testset "subset" begin
        @test Set() ⊆ U
        @test Set(["Hello World"]) ⊆ U
        @test Set(1:10) ⊆ U
        @test Set([:a, 2.0, "w", Set()]) ⊆ U
        @test U ⊆ U
    end
end

Vi kan sedan börja implementera vår funktionalitet tills den klarar våra tester. Det första steget är att definiera typen:

immutable UniversalSet <: Base.AbstractSet end

Endast två av våra test klarar just nu. Vi kan implementera in :

immutable UniversalSet <: Base.AbstractSet end
Base.in(x, ::UniversalSet) = true

Detta gör också att några av våra delmätningstester klarar. Emellertid issubset ( ) fallback inte för UniversalSet , eftersom fallbacken försöker iterera över element, vilket vi inte kan göra. Vi kan helt enkelt definiera en specialisering som gör att issubset true för alla uppsättningar:

immutable UniversalSet <: Base.AbstractSet end
Base.in(x, ::UniversalSet) = true
Base.issubset(x::Base.AbstractSet, ::UniversalSet) = true

Och nu klarar alla våra test!

Testa undantag

Undantag som uppstår vid körning av ett test kommer att misslyckas med testet, och om testet inte finns i en testuppsättning, avsluta testmotorn. Vanligtvis är detta bra, för i de flesta situationer är undantag inte det önskade resultatet. Men ibland vill man testa specifikt att ett visst undantag tas upp. @test_throws underlättar detta.

julia> @test_throws BoundsError [1, 2, 3][4]
Test Passed
  Expression: ([1,2,3])[4]
      Thrown: BoundsError

Om fel undantag kastas kommer @test_throws fortfarande att misslyckas:

julia> @test_throws TypeError [1, 2, 3][4]
Test Failed
  Expression: ([1,2,3])[4]
    Expected: TypeError
      Thrown: BoundsError
ERROR: There was an error during testing
 in record(::Base.Test.FallbackTestSet, ::Base.Test.Fail) at ./test.jl:397
 in do_test_throws(::Base.Test.Threw, ::Expr, ::Type{T}) at ./test.jl:329

och om inget undantag kastas kommer @test_throws att misslyckas också:

julia> @test_throws BoundsError [1, 2, 3, 4][4]
Test Failed
  Expression: ([1,2,3,4])[4]
    Expected: BoundsError
  No exception thrown
ERROR: There was an error during testing
 in record(::Base.Test.FallbackTestSet, ::Base.Test.Fail) at ./test.jl:397
 in do_test_throws(::Base.Test.Returned, ::Expr, ::Type{T}) at ./test.jl:329

Testa flytande punkt Ungefärlig jämlikhet

Vad är det med följande?

julia> @test 0.1 + 0.2 == 0.3
Test Failed
  Expression: 0.1 + 0.2 == 0.3
   Evaluated: 0.30000000000000004 == 0.3
ERROR: There was an error during testing
 in record(::Base.Test.FallbackTestSet, ::Base.Test.Fail) at ./test.jl:397
 in do_test(::Base.Test.Returned, ::Expr) at ./test.jl:281

Felet orsakas av att ingen av 0.1 , 0.2 och 0.3 representeras i datorn som exakt dessa värden - 1//10 , 2//10 och 3//10 . Istället är de ungefärliga av värden som är mycket nära. Men som framgår av testfelet ovan kan resultatet, när man lägger till två approximationer tillsammans, vara en något sämre tillnärmning än vad som är möjligt. Det finns mycket mer till detta ämne som inte kan behandlas här.

Men vi har ingen tur! För att testa att kombinationen av avrundning till ett flytande punktnummer och flyttalsaritmetik är ungefär korrekt, även om inte exakt, kan vi använda isapprox funktionen (som motsvarar operatören ). Så vi kan skriva om vårt test som

julia> @test 0.1 + 0.2 ≈ 0.3
Test Passed
  Expression: 0.1 + 0.2 ≈ 0.3
   Evaluated: 0.30000000000000004 isapprox 0.3

Naturligtvis, om vår kod var helt fel, kommer testet fortfarande att fånga det:

julia> @test 0.1 + 0.2 ≈ 0.4
Test Failed
  Expression: 0.1 + 0.2 ≈ 0.4
   Evaluated: 0.30000000000000004 isapprox 0.4
ERROR: There was an error during testing
 in record(::Base.Test.FallbackTestSet, ::Base.Test.Fail) at ./test.jl:397
 in do_test(::Base.Test.Returned, ::Expr) at ./test.jl:281

isapprox funktionen använder heuristik baserat på storleken på siffrorna och precisionen för flytpunkttypen för att bestämma mängden fel som ska tolereras. Det är inte lämpligt för alla situationer, men det fungerar i de flesta och sparar mycket ansträngning för att genomföra sin egen version av isapprox .



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow