Suche…


Syntax

  • @test [Ausdruck]
  • @test_throws [Ausnahme] [Ausdruck]
  • @testset "[Name]" begin; [Tests]; Ende
  • Pkg.test ([Paket])

Bemerkungen

Die Standard-Bibliotheksdokumentation für Base.Test umfasst zusätzliches Material, das über das in diesen Beispielen gezeigte hinausgeht.

Paket testen

Verwenden Sie zum Pkg.test der Pkg.test für ein Paket die Funktion Pkg.test . Für ein Paket mit dem Namen MyPackage der Befehl

julia> Pkg.test("MyPackage")

Eine erwartete Ausgabe wäre ähnlich

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

Natürlich kann man nicht erwarten, dass es genau mit den oben genannten übereinstimmt, da verschiedene Pakete unterschiedliche Frameworks verwenden.

Dieser Befehl führt die Datei test/runtests.jl des Pakets in einer sauberen Umgebung aus.

Mit können Sie alle installierten Pakete gleichzeitig testen

julia> Pkg.test()

Dies dauert jedoch normalerweise sehr lange.

Einen einfachen Test schreiben

Unit-Tests werden in der Datei test/runtests.jl in einem Paket deklariert. Normalerweise beginnt diese Datei

using MyModule
using Base.Test

Die grundlegende @test ist das @test Makro. Dieses Makro ist eine Art Behauptung. Jeder boolesche Ausdruck kann im @test Makro getestet werden:

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

Wir können das @test Makro in der REPL ausprobieren:

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

Das Testmakro kann fast überall verwendet werden, beispielsweise in Schleifen oder Funktionen:

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

Test-Set schreiben

0,5,0

In Version v0.5 sind Testsätze in die Standardbibliothek Base.Test , und Sie müssen keine besonderen using Base.Test (außer using Base.Test ), um sie verwenden zu können.

0,4,0

Test - Sets sind nicht Teil der von Julia v0.4 Base.Test Bibliothek. Stattdessen müssen Sie REQUIRE das BaseTestNext Modul, und fügen Sie using BaseTestNext zu Ihrer Datei. Um beide Versionen 0.4 und 0.5 zu unterstützen, können Sie verwenden

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

Es ist hilfreich, verwandte @test Tests in einem Test-Set zusammenzufassen. Zusätzlich zu einer übersichtlicheren Testorganisation bieten Testsets eine bessere Ausgabe und mehr Anpassbarkeit.

Um ein @test zu definieren, wickeln Sie einfach eine beliebige Anzahl von @test mit einem @testset Block ein:

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

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

Beim Ausführen dieser Testsätze wird die folgende Ausgabe gedruckt:

Test Summary: | Pass  Total
  +           |    2      2

Test Summary: | Pass  Total
  *           |    2      2

Selbst wenn ein Testsatz einen fehlerhaften Test enthält, wird der gesamte Testsatz vollständig ausgeführt und die Fehler werden aufgezeichnet und gemeldet:

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

Das Ausführen dieses Testsatzes führt zu

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

Testsätze können geschachtelt werden, um eine beliebig tiefe Organisation zu ermöglichen

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

Wenn die Tests erfolgreich sind, werden nur die Ergebnisse für den äußersten Testsatz angezeigt:

Test Summary: | Pass  Total
  Int         |    3      3

Wenn die Tests fehlschlagen, wird ein Drilldown in den genauen Testsatz und den Test, der den Fehler verursacht, gemeldet.

Das @testset Makro kann mit einer for Schleife verwendet werden , um viele Testsätze gleichzeitig zu erstellen:

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

welche berichtet

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

Eine übliche Struktur besteht darin, äußere Testsätze Komponenten oder Typen prüfen zu lassen. Innerhalb dieser äußeren Testsätze wird durch das innere Testverhalten das Testverhalten festgelegt. Angenommen, wir haben einen Typ UniversalSet mit einer Einzelinstanz erstellt, die alles enthält. Bevor wir den Typ überhaupt implementieren, können wir testgetriebene Entwicklungsprinzipien anwenden und die Tests implementieren:

@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

Wir können dann mit der Implementierung unserer Funktionalität beginnen, bis unsere Tests bestanden sind. Der erste Schritt ist die Definition des Typs:

immutable UniversalSet <: Base.AbstractSet end

Nur zwei unserer Tests bestehen im Moment. Wir können implementieren in :

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

Damit sind auch einige unserer Teilmengenprüfungen erfolgreich. Das issubset ( ) -Fallback funktioniert jedoch nicht für UniversalSet , da das Fallback versucht, Elemente zu durchlaufen, was wir nicht tun können. Wir können einfach eine Spezialisierung definieren, die issubset , dass issubset für jede Menge true :

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

Und jetzt bestehen alle unsere Tests!

Ausnahmen testen

Ausnahmen, die während eines Tests aufgetreten sind, schlagen fehl, und wenn der Test nicht in einem Testsatz enthalten ist, beenden Sie den Testmotor. Dies ist normalerweise eine gute Sache, da in den meisten Fällen Ausnahmen nicht das gewünschte Ergebnis sind. Aber manchmal möchte man speziell testen, dass eine bestimmte Ausnahme ausgelöst wird. Das Makro @test_throws erleichtert dies.

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

Wenn die falsche Ausnahme ausgelöst wird, @test_throws immer noch fehl:

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

und wenn keine Ausnahme ausgelöst wird, @test_throws ebenfalls fehl:

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

Prüfung des Fließpunkts Ungefährer Gleichwert

Was ist der Deal mit dem Folgenden?

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

Der Fehler wird durch die Tatsache verursacht, dass keine der Werte 0.1 , 0.2 und 0.3 im Computer als genau die Werte dargestellt werden - 1//10 , 2//10 und 3//10 . Sie werden stattdessen durch sehr nahe Werte angeglichen. Wie aus dem obigen Testfehler hervorgeht, kann das Ergebnis beim Hinzufügen von zwei Näherungen eine etwas schlechtere Näherung sein, als dies möglich ist. Es gibt noch viel mehr zu diesem Thema , das hier nicht behandelt werden kann.

Aber wir haben kein Glück! Um zu testen, ob die Kombination aus Rundung auf eine Fließkommazahl und Fließkomma-Arithmetik annähernd korrekt ist, auch wenn sie nicht genau ist, können wir die Funktion isapprox (die dem Operator ) verwenden. So können wir unseren Test als neu schreiben

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

Wenn unser Code völlig falsch war, wird der Test das natürlich trotzdem feststellen:

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

Die isapprox Funktion verwendet Heuristiken basierend auf der Größe der Zahlen und der Genauigkeit des Gleitkommatyps, um die zu tolerierende Fehlermenge zu bestimmen. Es ist nicht für alle Situationen geeignet, funktioniert aber in den meisten isapprox und erspart viel Aufwand bei der Implementierung der eigenen Version von isapprox .



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow