Spec-Zone.ru › Julia 1.8

Тестирование модулей

Тестирование базовой Julia

Julia активно развивается и имеет обширную тестовую базу для проверки работоспособности на нескольких платформах. Если вы собираете Julia из исходного кода, вы можете запустить эту тестовую базу с помощью make test. В случае бинарной установки тестовую базу можно запустить с помощью Base.runtests().

Base.runtestsФункция

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

Запустить тесты модулей Julia, перечисленные в tests, которые могут быть строкой или массивом строк, используя процессоры ncores. Если exit_on_error равно false, при провале одного теста все оставшиеся тесты в других файлах всё равно будут запущены; в противном случае они будут пропущены, когда exit_on_error == true. Если revise равно true, используется пакет Revise, чтобы загрузить любые изменения в Base или стандартные библиотеки перед запуском тестов. Если начальное значение предоставлено через ключевой аргумент, оно используется для инициализации глобального генератора случайных чисел в контексте выполнения тестов; в противном случае начальное значение выбирается случайным образом.

исходный код

Базовые модульные тесты

Модуль Test предоставляет простую функциональность модульного тестирования. Модульное тестирование — это способ проверить правильность вашего кода, убедившись, что результаты соответствуют ожидаемым. Это может быть полезно для обеспечения работоспособности кода после внесения изменений и может быть использовано при разработке для спецификации поведения вашего кода в завершенном виде. Также вы можете ознакомиться с документацией по добавлению тестов в ваш пакет Julia.

Простые модульные тесты можно выполнить с помощью макросов @test и @test_throws:

Test.@testМакрос

@test ex
@test f(args...) key=val ...
@test ex broken=true
@test ex skip=true

Проверить, что выражение ex вычисляется до true. Если выполняется внутри @testset, вернуть Pass Result, если это так, Fail Result, если это false, и Error Result, если оно не может быть вычислено. Если выполняется вне @testset, вместо возврата Fail или Error сгенерировать исключение.

Примеры

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). Не допускается передавать более одного выражения, если первое не является выражением вызова, а остальные — присваиваниями (k=v).

Вы можете использовать любые ключи для аргументов key=val, кроме broken и skip, которые имеют специальное значение в контексте @test:

  • broken=cond указывает на тест, который должен пройти, но в настоящее время постоянно терпит неудачу, когда cond==true. Тестирует, что выражение ex вычисляется до false или вызывает исключение. Возвращает Broken Result в случае успеха, или Error Result если выражение вычисляется до true. Регулярное @test ex вычисляется при cond==false.
  • skip=cond отмечает тест, который не должен выполняться, но должен включаться в отчет о результатах тестов как Broken, когда cond==true. Это может быть полезно для тестов, которые периодически завершаются неудачей, или тестов для ещё не реализованной функциональности. Регулярное @test ex вычисляется при cond==false.

Примеры

julia> @test 2 + 2 ≈ 6 atol=1 broken=true
Test Broken
  Expression: ≈(2 + 2, 6, atol = 1)

julia> @test 2 + 2 ≈ 5 atol=1 broken=false
Test Passed

julia> @test 2 + 2 == 5 skip=true
Test Broken
  Skipped: 2 + 2 == 5

julia> @test 2 + 2 == 4 skip=false
Test Passed

Ключевые аргументы broken и skip требуют как минимум Julia 1.7.

Test.@test_throwsМакрос

@test_throws exception expr

Тестирует, что выражение expr вызывает exception. Исключение может указывать тип, строку, регулярное выражение или список строк, встречающихся в сообщении об ошибке, функцию сопоставления или значение (которое будет проверено на равенство путем сравнения полей). Обратите внимание, что @test_throws не поддерживает форму с ключевым аргументом в конце.

Возможность указать что-либо кроме типа или значения как exception требует Julia v1.8 или более поздней версии.

Примеры

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 will only return a complex result if called with a complex argument. Try sqrt(Complex(x))."

В последнем примере вместо сопоставления одной строки можно было бы использовать:

  • ["Try", "Complex"] (список строк)
  • r"Try sqrt\([Cc]omplex" (регулярное выражение)
  • str -> occursin("complex", str) (функция сопоставления)

Например, предположим, что мы хотим проверить, что наша новая функция 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 для проверки этого:

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

Работа с наборами тестов

Обычно используется большое количество тестов, чтобы убедиться, что функции работают корректно на широком диапазоне входных данных. В случае неудачи теста по умолчанию происходит немедленное генерирование исключения. Однако обычно предпочтительнее сначала выполнить оставшиеся тесты, чтобы лучше понять, сколько ошибок содержится в тестируемом коде.

@testset создаст локальную область видимости при запуске тестов внутри неё.

Макрос @testset может использоваться для группировки тестов в наборы. Все тесты в наборе будут запущены, и в конце набора будет напечатан сводный отчёт. Если какие-либо тесты завершились неудачей или не удалось их вычислить из-за ошибки, набор тестов сгенерирует TestSetException.

Test.@testsetМакрос

@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
@testset [CustomTestSet] [option=val  ...] ["description $v, $w"] foo()

Начинает новый набор тестов или несколько наборов тестов, если используется цикл for.

Если тип набора тестов не указан, по умолчанию создаётся DefaultTestSet. DefaultTestSet записывает все результаты и, если имеются какие-либо Fail или Error , генерирует исключение в конце верхнеуровневого (не вложенного) набора тестов вместе со сводкой результатов тестов.

Можно указать любой пользовательский тип набора тестов (подтип AbstractTestSet) и он будет использоваться для всех вложенных вызовов @testset . Указанные параметры применяются только к набору тестов, где они указаны. Тип набора тестов по умолчанию принимает два логических параметра:

  • verbose: если true, сводная информация по результатам вложенных наборов тестов отображается даже

когда все они пройдены (по умолчанию false).

  • showtiming: если true, отображается время выполнения каждого набора тестов

(по умолчанию true).

@testset foo() требует как минимум Julia 1.8.

Строка описания поддерживает интерполяцию из индексов цикла. Если описание не указано, оно генерируется на основе переменных. Если указан вызов функции, будет использовано её имя. Явные строки описания переопределяют это поведение.

По умолчанию макрос @testset возвращает сам объект набора тестов, хотя это поведение можно настроить в других типах наборов тестов. Если используется цикл for , макрос собирает и возвращает список возвращаемых значений метода finish , который по умолчанию возвращает список объектов наборов тестов, использованных в каждом итерационном шаге.

Перед выполнением тела @testset, неявно вызывается Random.seed!(seed), где seed — текущее начальное значение глобального генератора случайных чисел. Кроме того, после выполнения тела состояние глобального генератора случайных чисел восстанавливается до состояния, существовавшего до вызова @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  Time
trigonometric identities |    4      4  0.2s

Test.TestSetExceptionТип

TestSetException

Генерируется, когда набор тестов завершается, и не все тесты прошли успешно.

Мы можем поместить наши тесты для функции foo(x) в набор тестов:

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

Наборы тестов также могут быть вложенными:

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

А также вызывать функции:

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

Это можно использовать для факторизации наборов тестов, что облегчает запуск отдельных наборов тестов путём запуска соответствующих функций. Обратите внимание, что в случае функций набор тестов будет получать имя вызываемой функции. В случае, если вложенный набор тестов не содержит неудач, как это произошло здесь, он будет скрыт в сводке, если не будет передан параметр verbose=true:

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

Если у нас есть неудача в тесте, будут отображены только детали неудачных наборов тестов:

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.

Тестирование операторов регистрации

Можно использовать макрос @test_logs для тестирования операторов регистрации или использовать TestLogger.

Test.@test_logsМакрос

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

Соберите список записей журнала, сгенерированных expression с помощью collect_test_logs, проверьте, что они соответствуют последовательности log_patterns, и верните значение expression. keywords предоставляют некоторую простую фильтрацию записей журнала: ключевое слово min_level управляет минимальным уровнем журнала, который будет собран для теста, ключевое слово match_mode определяет, как будет выполняться соответствие (по умолчанию :all проверяет, что все журналы и шаблоны соответствуют попарно; используйте :any для проверки, что шаблон соответствует хотя бы один раз где-то в последовательности.)

Наиболее полезный шаблон журнала — это простая кортеж формата (level,message). Разное количество элементов кортежа может быть использовано для сопоставления других метаданных журнала, соответствующих аргументам, переданным AbstractLogger через функцию handle_message: (level,message,module,group,id,file,line). Элементы, которые присутствуют, будут сопоставляться попарно с полями записей журнала по умолчанию с использованием ==, со специальными случаями, что Symbol могут использоваться для стандартных уровней журнала, и Regex в шаблоне будут соответствовать строковым или Символьным полям, используя occursin.

Примеры

Рассмотрим функцию, которая записывает предупреждение и несколько сообщений отладки:

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

Мы можем протестировать сообщение info с помощью

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

Если мы также хотели протестировать сообщения отладки, их необходимо включить с помощью ключевого слова min_level:

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

Если вы хотите проверить, что генерируются некоторые конкретные сообщения, игнорируя остальные, вы можете установить ключевое слово match_mode=:any:

using Logging
@test_logs (:info,) (:debug,"Iteration 42") min_level=Logging.Debug match_mode=:any foo(100)

Макрос может быть связан с @test для тестирования возвращаемого значения:

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

Если вы хотите проверить отсутствие предупреждений, вы можете опустить указание шаблонов журналов и соответственно установить min_level:

# test that the expression logs no messages when the logger level is warn:
@test_logs min_level=Logging.Warn @info("Some information") # passes
@test_logs min_level=Logging.Warn @warn("Some information") # fails

Если вы хотите проверить отсутствие предупреждений (или сообщений об ошибках) в stderr, которые не генерируются @warn, см. @test_nowarn.

Test.TestLoggerТип

TestLogger(; min_level=Info, catch_exceptions=false)

Создайте TestLogger, который захватывает записанные сообщения в своем поле logs::Vector{LogRecord}.

Установите min_level для управления LogLevel, catch_exceptions для того, чтобы исключить или включить обработку исключений, сгенерированных в процессе создания событий журнала, и respect_maxlog для того, чтобы следовать соглашению о записи сообщений с maxlog=n для некоторого целого n не более n раз.

См. также: LogRecord.

Пример

julia> using Test, Logging

julia> f() = @info "Hi" number=5;

julia> test_logger = TestLogger();

julia> with_logger(test_logger) do
           f()
           @info "Bye!"
       end

julia> @test test_logger.logs[1].message == "Hi"
Test Passed

julia> @test test_logger.logs[1].kwargs[:number] == 5
Test Passed

julia> @test test_logger.logs[2].message == "Bye!"
Test Passed

Test.LogRecordТип

LogRecord

Хранит результаты одного события журнала. Поля:

  • level: LogLevel сообщения журнала
  • message: текстовое содержание сообщения журнала
  • _module: модуль события журнала
  • group: группа журналов (по умолчанию, имя файла, содержащего событие журнала)
  • id: идентификатор события журнала
  • file: файл, содержащий событие журнала
  • line: строка в файле события журнала
  • kwargs: любые ключевые аргументы, переданные в событие журнала

Другие макросы тестов

Так как вычисления с плавающей точкой могут быть неточными, вы можете выполнить проверки приблизительного равенства, используя либо @test a ≈ b (где ≈, набираемый с помощью автодополнения \approx, является функцией 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

Вы можете указать относительные и абсолютные погрешности, установив ключевые аргументы rtol и atol функции isapprox, соответственно, после сравнения ≈:

julia> @test 1 ≈ 0.999999  rtol=1e-5
Test Passed

Обратите внимание, что это не специфическая функция ≈, а скорее общая функция макроса @test: @test a <op> b key=val преобразуется макросом в @test op(a, b, key=val). Однако это особенно полезно для тестов ≈.

Test.@inferredМакрос

@inferred [AllowedType] f(x)

Проверяет, что выражение вызова f(x) возвращает значение того же типа, что и выведено компилятором. Это полезно для проверки стабильности типа.

f(x) может быть любым выражением вызова. Возвращает результат f(x) если типы совпадают, и Error Result если обнаружит разные типы.

Необязательно, AllowedType ослабляет тест, сделав его проходящим, когда тип f(x) соответствует выведенному типу с учётом AllowedType, или когда возвращаемый тип является подтипом AllowedType. Это полезно при тестировании стабильности типа функций, возвращающих небольшое объединение типов, например Union{Nothing, T} или Union{Missing, T}.

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) in Main at 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)
ERROR: return type Int64 does not match inferred return type Union{Float64, Int64}
[...]

julia> @inferred max(1, 2)
2

julia> g(a) = a < 10 ? missing : 1.0
g (generic function with 1 method)

julia> @inferred g(20)
ERROR: return type Float64 does not match inferred return type Union{Missing, Float64}
[...]

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)
ERROR: return type Int64 does not match inferred return type Union{Missing, Float64, Int64}
[...]

Test.@test_deprecatedМакрос

@test_deprecated [pattern] expression

Если --depwarn=yes, проверит, что expression генерирует предупреждение о устаревании и возвращает значение 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"

Test.@test_warnМакрос

@test_warn msg expr

Проверяет, приводит ли вычисление expr к выводу в stderr, который содержит строку msg или соответствует регулярному выражению msg. Если msg — это булево выражение, проверяет, возвращает ли msg(output) значение true. Если msg — это кортеж или массив, проверяет, что вывод об ошибке содержит/соответствует каждому элементу в msg. Возвращает результат вычисления expr.

См. также @test_nowarn для проверки отсутствия вывода об ошибке.

Примечание: Предупреждения, сгенерированные @warn не могут быть проверены с помощью этого макроса. Используйте @test_logs вместо этого.

Test.@test_nowarnМакрос

@test_nowarn expr

Проверяет, приводит ли вычисление expr к пустому выводу в stderr (нет предупреждений или других сообщений). Возвращает результат вычисления expr.

Примечание: Отсутствие предупреждений, сгенерированных @warn не может быть проверено с помощью этого макроса. Используйте @test_logs вместо этого.

Неисправные тесты

Если тест последовательно терпит неудачу, его можно изменить с помощью макроса @test_broken. Это обозначит тест как Broken , если тест продолжает терпит неудачу, и оповестит пользователя с помощью Error , если тест пройден.

Test.@test_brokenМакрос

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

Указывает на тест, который должен пройти, но в настоящее время последовательно терпит неудачу. Проверяет, что выражение ex вычисляется до false или вызывает исключение. Возвращает Broken Result если это так, или Error Result , если выражение вычисляется до true. Это эквивалентно @test ex broken=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)

Также доступен @test_skip, чтобы пропустить тест без оценки, но учитывая пропущенный тест в отчёте о тестировании. Тест не будет выполнен, но выдаст Broken Result.

Test.@test_skipМакрос

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

Помечает тест, который не должен выполняться, но должен быть включён в отчёт о тестировании как Broken. Это может быть полезно для тестов, которые периодически терпят неудачу, или для тестов ещё не реализованной функциональности. Это эквивалентно @test ex skip=true.

Форма @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)

Создание пользовательских типов AbstractTestSet

Пакеты могут создавать собственные подтипы AbstractTestSet путём реализации методов record и finish. Подтип должен иметь конструктор с одним аргументом, принимающим строку описания, а все опции передаются в виде ключевых аргументов.

Test.recordФункция

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

Записывает результат в тестовый набор. Эта функция вызывается инфраструктурой @testset каждый раз, когда завершается содержащий @test макрос, и получает результат теста (который может быть Error). Она также будет вызвана с Error если во время выполнения блока теста будет выброшено исключение вне контекста @test.

Test.finishФункция

finish(ts::AbstractTestSet)

Выполните все необходимые окончательные обработки для данного набора тестов. Это вызывается инфраструктурой @testset после выполнения блока тестов.

Пользовательские подтипы AbstractTestSet должны вызывать record у своего родительского элемента (если он есть), чтобы добавить себя в дерево результатов тестов. Это может быть реализовано следующим образом:

if get_testset_depth() != 0
    # Attach this test set to the parent test set
    parent_ts = get_testset()
    record(parent_ts, self)
    return self
end

Test несет ответственность за поддержание стека вложенных наборов тестов по мере их выполнения, но любая аккумуляция результатов является обязанностью подтипа AbstractTestSet. Вы можете получить доступ к этому стеку с помощью методов get_testset и get_testset_depth. Обратите внимание, что эти функции не экспортируются.

Test.get_testsetФункция

get_testset()

Получить активный набор тестов из локального хранилища задачи. Если активного набора тестов нет, используется резервный набор тестов по умолчанию.

Test.get_testset_depthФункция

get_testset_depth()

Возвращает количество активных наборов тестов, не включая набор тестов по умолчанию.

Test также гарантирует, что вложенные вызовы @testset используют тот же подтип AbstractTestSet , что и их родительский элемент, если явно не указан другой. Он не распространяет никаких свойств набора тестов. Поведение наследования опций может быть реализовано пакетами, использующими инфраструктуру стека, которую предоставляет Test.

Определение базового подтипа AbstractTestSet может выглядеть так:

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

Утилиты тестирования

Test.GenericArrayТип

GenericArray может использоваться для тестирования общих API массивов, ориентированных на интерфейс AbstractArray, чтобы убедиться, что функции могут работать с типами массивов помимо стандартного типа Array.

Test.GenericDictТип

GenericDict может использоваться для тестирования общих API словарей, ориентированных на интерфейс AbstractDict, чтобы убедиться, что функции могут работать с ассоциативными типами помимо стандартного типа Dict.

Test.GenericOrderТип

GenericOrder может использоваться для тестирования API, поддерживающих общие упорядоченные типы.

Test.GenericSetТип

GenericSet может использоваться для тестирования общих API множеств, ориентированных на интерфейс AbstractSet, чтобы убедиться, что функции могут работать с типами множеств помимо стандартных типов Set и BitSet.

Test.GenericStringТип

GenericString может использоваться для тестирования общих API строк, ориентированных на интерфейс AbstractString, чтобы убедиться, что функции могут работать со строковыми типами помимо стандартного типа String.

Test.detect_ambiguitiesФункция

detect_ambiguities(mod1, mod2...; recursive=false,
                                  ambiguous_bottom=false,
                                  allowed_undefineds=nothing)

Возвращает вектор пар (Method,Method) неопределенных методов, определенных в указанных модулях. Используйте recursive=true для тестирования во всех подмодулях.

ambiguous_bottom управляет включением в результат только тех неопределённостей, которые вызваны параметрами типа Union{}; в большинстве случаев вы, вероятно, захотите установить это значение в false. Смотрите Base.isambiguous.

См. Test.detect_unbound_args для объяснения allowed_undefineds.

allowed_undefineds требует по крайней мере Julia 1.8.

Test.detect_unbound_argsФункция

detect_unbound_args(mod1, mod2...; recursive=false, allowed_undefineds=nothing)

Возвращает вектор Method , которые могут иметь неопределенные типы параметров. Используйте recursive=true для тестирования во всех подмодулях.

По умолчанию любые неопределенные символы вызывают предупреждение. Это предупреждение можно подавить, указав коллекцию GlobalRef , для которых можно пропустить предупреждение. Например, установка

allow_undefineds = Set([GlobalRef(Base, :active_repl),
                        GlobalRef(Base, :active_repl_backend)])

позволила бы подавить предупреждения о Base.active_repl и Base.active_repl_backend.

allowed_undefineds требует по крайней мере Julia 1.8.

© 2009–2022 Jeff Bezanson, Stefan Karpinski, Viral B. Shah, and other contributors
Licensed under the MIT License.
https://docs.julialang.org/en/v1.8/stdlib/Test/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API