iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 22
0

為什麼要來看一下unit test呢?

老實說,我本身並不具有資訊工程相關背景,一開始也沒聽過什麼unit test。但自從踏入了生物資訊這個領域,隨著開發的東西增加,同時還有需要寫一些比較大型的專案,很多問題也跟著衍生出來。一直到了某次偶然的機會聽到了這個詞,還看到了別人怎麼在R語言的專案裡頭引入unit test這個東西,才開始理解這個步驟的意義。因此,為了寫好一個julia的專案,了解一下這個語言裡頭有哪些相應的工具可用也是必須的。

Julia裡頭本身就提供了一套很方便的unit test工具 - Test

在Julia底下直接就有個Test的package可使用,它的使用方法也非常容易,直接呼叫它提供的macro

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

來看幾個實際的例子:

using Test
julia> x = "b"
"b"
julia> @test typeof(x) == String
Test Passed
julia> @test 5.0/3 ≈ 1.67 atol=0.01
Test Passed

另外,我們也可以用@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
julia> foo(x) = length(x)^2
julia> @test_throws MethodError foo(:cat)
Test Passed
      Thrown: MethodError

這樣一個一個測試終歸是麻煩且凌亂,有沒有辦法可以整理在一起、分門別類地做測試呢? 可以!用@testsetbegin區塊:

julia> @testset "Foo()測試" begin
           @test foo("a") == 1
           @test foo("ab") == 4
           @test foo("abc") == 9
       end
Test Summary: | Pass  Total
Foo()測試      |    3      3
Test.DefaultTestSet("Foo()測試", Any[], 3, false)

julia> @testset "三角函數測試" 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
三角函數測試    |    4      4
Test.DefaultTestSet("三角函數測試", Any[], 4, false)

如果是寫一個Package的話,還可以充分利用巢狀結構來針對不同的module做測試,或是對同一個module做不同類型的測試:

julia> @testset "foo函數詳細測試" 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函數詳細測試 |    8      8
Test.DefaultTestSet("foo函數詳細測試", Any[DefaultTestSet("Animals", Any[], 2, false), DefaultTestSet("Arrays 1", Any[], 2, false), DefaultTestSet("Arrays 2", Any[], 2, false), DefaultTestSet("Arrays 3", Any[], 2, false)], 0, false)

除了這些之外,我們還可以用@infer測試函數的返回值是否如預期

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:
 [1] error(::String) at ./error.jl:33
 [2] top-level scope at none:0
julia> @inferred max(1, 2)
2

另外根據官方文件說,他們還支援了@test_logs,但我根據說明文件操作時julia卻拋出錯誤訊息,不知有沒有人遇過這種情況?

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

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

julia> @test_logs (:info,"Doing foo with n=2") (:debug,"Iteration 1") (:debug,"Iteration 2") min_level=Debug foo(2)
Error During Test at REPL[45]:1
  Test threw exception
  Expression: foo(2)
  UndefVarError: Debug not defined
  Stacktrace:
   [1] top-level scope at none:0
   [2] eval(::Module, ::Any) at ./boot.jl:319
   [3] eval_user_input(::Any, ::REPL.REPLBackend) at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.0/REPL/src/REPL.jl:85
   [4] macro expansion at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.0/REPL/src/REPL.jl:117 [inlined]
   [5] (::getfield(REPL, Symbol("##28#29")){REPL.REPLBackend})() at ./task.jl:259
ERROR: There was an error during testing

上一篇
[Day 21] 回頭看一下Julia裡頭的一些規範
下一篇
[Day 23] 今天練習用Julia寫HMM-forward
系列文
When Bioinfo met Julia: Bioinformatician的30天Julia學習之路32

1 則留言

0
杜岳華
iT邦新手 5 級 ‧ 2018-10-23 22:09:27

已經到了測試工具了啊~~~

那你有沒有興趣寫寫 log 工具呢XD
https://discourse.julialang.org/t/recommendation-for-logging/4560

或是進度條
https://github.com/timholy/ProgressMeter.jl

推推

@杜岳華,研究一下再跟你說 XD

我要留言

立即登入留言