Recherche…


Syntaxe

  • @test [expr]
  • @test_throws [Exception] [expr]
  • @testset "[nom]" commence; [tests] fin
  • Pkg.test ([package])

Remarques

La documentation standard de la bibliothèque pour Base.Test couvre le matériel supplémentaire au-delà de celui montré dans ces exemples.

Test d'un package

Pour exécuter les tests unitaires pour un package, utilisez la fonction Pkg.test . Pour un paquet nommé MyPackage , la commande serait

julia> Pkg.test("MyPackage")

Une sortie attendue serait similaire à

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

Bien évidemment, on ne peut pas s’attendre à ce qu’il corresponde exactement à ce qui précède, car différents packages utilisent des frameworks différents.

Cette commande exécute le fichier test/runtests.jl du test/runtests.jl dans un environnement propre.

On peut tester tous les paquets installés en même temps avec

julia> Pkg.test()

mais cela prend généralement beaucoup de temps.

Écrire un test simple

Les tests unitaires sont déclarés dans le fichier test/runtests.jl dans un package. En règle générale, ce fichier commence

using MyModule
using Base.Test

L'unité de base de test est la macro @test . Cette macro est comme une assertion de toutes sortes. Toute expression booléenne peut être testée dans la macro @test :

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

Nous pouvons essayer la macro @test dans le 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

La macro de test peut être utilisée à peu près partout, comme dans les boucles ou les fonctions:

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

Ecrire un jeu de test

0.5.0

Dans la version v0.5, les ensembles de tests sont intégrés au module Base.Test bibliothèque standard et vous n'avez rien à faire de particulier (en plus d' using Base.Test ) pour les utiliser.

0.4.0

Les jeux de tests ne font pas partie de la bibliothèque Base.Test de Julia v0.4. Au lieu de cela, vous devez REQUIRE le module BaseTestNext et ajouter à l' using BaseTestNext à votre fichier. Pour prendre en charge les versions 0.4 et 0.5, vous pouvez utiliser

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

Il est utile de regrouper les @test associés dans un ensemble de tests. En plus d'une organisation de test plus claire, les ensembles de tests offrent de meilleurs résultats et une plus grande personnalisation.

Pour définir un ensemble de tests, @test tout nombre de @test s avec un bloc @testset :

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

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

L'exécution de ces jeux de tests imprime la sortie suivante:

Test Summary: | Pass  Total
  +           |    2      2

Test Summary: | Pass  Total
  *           |    2      2

Même si un ensemble de tests contient un test défaillant, l’ensemble de test sera exécuté jusqu’à la fin et les échecs seront enregistrés et signalés:

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

L'exécution de cet ensemble de tests entraîne

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

Les ensembles de tests peuvent être imbriqués, permettant une organisation arbitrairement profonde

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

Si les tests réussissent, cela affichera uniquement les résultats pour le test le plus externe:

Test Summary: | Pass  Total
  Int         |    3      3

Cependant, si les tests échouent, un rapport détaillé sur le jeu de tests exact et le test à l'origine de la panne est signalé.

La macro @testset peut être utilisée avec une boucle for pour créer plusieurs ensembles de tests à la fois:

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

qui rapporte

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

Une structure commune consiste à avoir des composants ou des types de test de jeux de tests externes. Dans ces ensembles de test externes, le test interne définit le comportement du test. Par exemple, supposons que nous ayons créé un type UniversalSet avec une instance singleton qui contient tout. Avant même d'implémenter le type, nous pouvons utiliser les principes de développement pilotés par les tests et implémenter les tests:

@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

Nous pouvons alors commencer à implémenter nos fonctionnalités jusqu'à ce qu'elles réussissent nos tests. La première étape consiste à définir le type:

immutable UniversalSet <: Base.AbstractSet end

Seulement deux de nos tests réussissent en ce moment. Nous pouvons mettre in œuvre in :

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

Cela fait également passer certains de nos tests de sous-ensemble. Cependant, le issubset ( ) ne fonctionne pas pour UniversalSet , car le repli essaie d'itérer sur les éléments, ce que nous ne pouvons pas faire. Nous pouvons simplement définir une spécialisation qui fait que issubset retourne true pour tout ensemble:

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

Et maintenant, tous nos tests réussissent!

Tester les exceptions

Les exceptions rencontrées lors de l'exécution d'un test échouent au test et si le test ne se trouve pas dans un ensemble de tests, fermez le moteur de test. Généralement, c'est une bonne chose, car dans la plupart des cas, les exceptions ne sont pas le résultat souhaité. Mais parfois, on veut tester spécifiquement qu'une certaine exception est soulevée. La macro @test_throws facilite cela.

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

Si la mauvaise exception est levée, @test_throws échouera toujours:

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

et si aucune exception n'est levée, @test_throws échouera également:

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

Test d'égalité approximative à virgule flottante

Quel est le problème avec ce qui suit?

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

L'erreur est causée par le fait qu'aucun des 0.1 , 0.2 et 0.3 n'est représenté dans l'ordinateur comme étant exactement ces valeurs - 1//10 , 2//10 et 3//10 . Au lieu de cela, ils sont approximés par des valeurs très proches. Mais comme on l'a vu dans l'échec du test ci-dessus, lors de l'ajout de deux approximations, le résultat peut être une approximation légèrement inférieure à celle possible. Il y a beaucoup plus à ce sujet qui ne peut pas être couvert ici.

Mais nous n'avons pas de chance! Pour vérifier que la combinaison de l'arrondi à un nombre à virgule flottante et de l'arithmétique à virgule flottante est approximativement correcte, même si elle n'est pas exacte, nous pouvons utiliser la fonction isapprox (qui correspond à l'opérateur ). Nous pouvons donc réécrire notre test en tant que

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

Bien sûr, si notre code était complètement faux, le test détectera toujours que:

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

La fonction isapprox utilise des isapprox heuristiques basées sur la taille des nombres et la précision du type à virgule flottante pour déterminer la quantité d'erreur à tolérer. Ce n'est pas approprié pour toutes les situations, mais cela fonctionne dans la plupart des cas, et permet d'économiser beaucoup d'efforts pour implémenter sa propre version d' isapprox .



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow