OCaml Variants and unit test

322 阅读2分钟

这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战

变体(Variants)

Ocaml 中的变体(variants)类似于枚举类型,用来表示多种可能的值。例如

utop # type day = Sun | Mon | Tue | Wed | Thu | Fri | Sat;;
type day = Sun | Mon | Tue | Wed | Thu | Fri | Sat

utop # let d = Tue;;
val d : day = Tue

变体(variant)的每一个单独的值在Ocaml中被称为构造器(constructors)。比如上面的例子中,SunMon就是构造器。

对于变体来说,构造非常的简单: 只用写出构造器的名字就可以;对于访问:我们使用模式匹配。例如:

utop # let int_of_day d = 
       match d with
       | Sun -> 1
       | Mon -> 2
       | Tue -> 3
       | Wed -> 4
       | Thu -> 5
       | Fri -> 6
       | Sat -> 7;;

val int_of_day : day -> int = <fun>

没有任何类型的将构造函数名称映射到 int 的自动方法,就像您对带有枚举的语言所期望的那样。

作用域

假设我们有两个类型拥有相同的构造器名字,例如

utop # type t1 = C | D;;
type t1 = C | D

utop # type t2 = D | E;;
type t2 = D | E

utop # let x = D;;
val x : t2 = D

我们可以发现最后的x的类型为t2

单元测试

我们这里列举一个单元测试的例子

比如,我们要测试如下代码,在sum.ml

let rec sum = function
  | [] -> 0
  | x :: xs -> x + sum xs

这里我们使用OUnit2来进行单元测试,安装OUnit2时使用opam OUnit2,写在test.ml

open OUnit2
open Sum

let tests = "test suite for sum" >::: [
  "empty" >:: (fun _ -> assert_equal 0 (sum []));
  "singleton" >:: (fun _ -> assert_equal 1 (sum [1]));
  "two_elements" >:: (fun _ -> assert_equal 3 (sum [1; 2]));
]
let _ = run_test_tt_main tests

我们详细的看其中的代码,

[
  "empty"  >:: (fun _ -> assert_equal 0 (sum []));
  "one"    >:: (fun _ -> assert_equal 1 (sum [1]));
  "onetwo" >:: (fun _ -> assert_equal 3 (sum [1; 2]));
]

每一行是单独的测试例子。在操作符>::的左边是测试例子的名字,右边是具体的函数。

运行前我们创建dune文件,

(executable
 (name test)
 (libraries ounit2))

然后我们编译,并得到结果

➜  Ocaml dune build test.exe
➜  Ocaml dune exec ./test.exe
...                  
Ran: 3 tests in: 0.11 seconds.
OK

现在我们假设我们修改了sum.ml并且增加一个bug在里面:

let rec sum = function
  | [] -> 1
  | x :: xs -> x + sum xs

我们同样的进行编译得到结果

➜  Ocaml dune exec ./test.exe
FFF                  
============================================================
Error: test suite for sum:1:singleton.
File "/Users/dcl/Documents/workspace/Ocaml/_build/oUnit-test suite for sum-dcl-2.local#02.log", line 2, characters 1-1:
Error: test suite for sum:1:singleton (in the log).
Raised at OUnitAssert.assert_failure in file "src/lib/ounit2/advanced/oUnitAssert.ml", line 45, characters 2-27
Called from OUnitRunner.run_one_test.(fun) in file "src/lib/ounit2/advanced/oUnitRunner.ml", line 83, characters 13-26
not equal

第一行的FFF暗示OUnit返回三个错误案例。