我覺得一切都是冠軍,但我是專門找:如何在ocaml中進行測試驅動開發?
- 什麼是「標準」的單元測試框架ocaml的?
- 如何在構建中集成執行測試?
- 如何在每次文件更改時自動執行測試?
作爲獎勵,我會感興趣的測試覆蓋率工具...
我覺得一切都是冠軍,但我是專門找:如何在ocaml中進行測試驅動開發?
作爲獎勵,我會感興趣的測試覆蓋率工具...
看來,包ounit享有相當大的人氣,還有其他幾個包像kaputt或broken - 我是後者的作者。
我想你有興趣作爲測試可以自動化的TDD的具體部分,下面是我如何在自己的項目上做到這一點。您可以在GitHub上找到幾個例子,例如Lemonade或Rashell,它們都在其各自的testsuite
文件夾中找到了測試套件。
我一般根據根據工作流程工作:
.mli
)文件同時工作,這樣我寫了一個最小的方案,不要只寫測試用例的功能我想要實現,但也有機會嘗試接口,以確保我有一個易於使用的界面。例如,對於該界面在Rashell_Posix發現find(1)
命令我開始寫test cases:
open Broken
open Rashell_Broken
open Rashell_Posix
open Lwt.Infix
let spec base = [
(true, 0o700, [ base; "a"]);
(true, 0o750, [ base; "a"; "b"]);
(false, 0o600, [ base; "a"; "b"; "x"]);
(false, 0o640, [ base; "a"; "y" ]);
(true, 0o700, [ base; "c"]);
(false, 0o200, [ base; "c"; "z"]);
]
let find_fixture =
let filename = ref "" in
let cwd = Unix.getcwd() in
let changeto base =
filename := base;
Unix.chdir base;
Lwt.return base
in
let populate base =
Toolbox.populate (spec base)
in
make_fixture
(fun() ->
Lwt_main.run
(Rashell_Mktemp.mktemp ~directory:true()
>>= changeto
>>= populate))
(fun() ->
Lwt_main.run
(Unix.chdir cwd;
rm ~force:true ~recursive:true [ !filename ]
|> Lwt_stream.junk_while (fun _ -> true)))
let assert_find id ?expected_failure ?workdir predicate lst =
assert_equal id ?expected_failure
~printer:(fun fft lst -> List.iter (fun x -> Format.fprintf fft " %S" x) lst)
(fun() -> Lwt_main.run(
find predicate [ "." ]
|> Lwt_stream.to_list
|> Lwt.map (List.filter ((<>) "."))
|> Lwt.map (List.sort Pervasives.compare)))
()
lst
的spec
和find_fixture
函數用於創建一個文件的層次結構與給定的名稱和權限,以鍛鍊find
功能。然後assert_find
函數準備一個測試用例進行比較的呼叫的結果,以find(1)
與預期結果:
let find_suite =
make_suite ~fixture:find_fixture "find" "Test suite for find(1)"
|& assert_find "regular" (Has_kind(S_REG)) [
"./a/b/x";
"./a/y";
"./c/z";
]
|& assert_find "directory" (Has_kind(S_DIR)) [
"./a";
"./a/b";
"./c"
]
|& assert_find "group_can_read" (Has_at_least_permission(0o040)) [
"./a/b";
"./a/y"
]
|& assert_find "exact_permission" (Has_exact_permission(0o640)) [
"./a/y";
]
同時我在寫on the interface file:
(** The type of file types. *)
type file_kind = Unix.file_kind =
| S_REG
| S_DIR
| S_CHR
| S_BLK
| S_LNK
| S_FIFO
| S_SOCK
(** File permissions. *)
type file_perm = Unix.file_perm
(** File status *)
type stats = Unix.stats = {
st_dev: int;
st_ino: int;
st_kind: file_kind;
st_perm: file_perm;
st_nlink: int;
st_uid: int;
st_gid: int;
st_rdev: int;
st_size: int;
st_atime: float;
st_mtime: float;
st_ctime: float;
}
type predicate =
| Prune
| Has_kind of file_kind
| Has_suffix of string
| Is_owned_by_user of int
| Is_owned_by_group of int
| Is_newer_than of string
| Has_exact_permission of int
| Has_at_least_permission of int
| Name of string (* Globbing pattern on basename *)
| And of predicate list
| Or of predicate list
| Not of predicate
val find :
?workdir:string ->
?env:string array ->
?follow:bool ->
?depthfirst:bool ->
?onefilesystem:bool ->
predicate -> string list -> string Lwt_stream.t
(** [find predicate pathlst] wrapper of the
{{:http://pubs.opengroup.org/onlinepubs/9699919799/utilities/find.html} find(1)}
command. *)
一旦我對測試用例和接口感到滿意,即使沒有實現,我也可以嘗試編譯它們。這可以通過bsdowl只需提供接口文件而不是Makefile中的實現文件來實現。 這裏的編譯可能在我的測試中發現了一些我可以修復的類型錯誤。
當針對接口編寫的測試,我可以實現的功能,從一個託辭功能:
讓找_ = failwith「Rashell_Posix。發現:未實現」。
有了這個實現我能夠編譯我的圖書館,我的測試套件在這一點上,當然,測試只是失敗
Rashell_Posix.find
功能和重複測試,直到他們通過。這是我做的測試驅動開發OCaml中,當我使用自動測試。有些人看到互動將REPL作爲測試驅動開發的一種形式,這是一項技術我也喜歡使用它,它的設置和使用相當簡單。在Rashell中使用後一種形式的測試驅動開發的唯一設置步驟是編寫一個.ocamlinit
文件,以便加載所有需要的庫。這個文件看起來像:
#use "topfind";;
#require "broken";;
#require "lemonade";;
#require "lwt.unix";;
#require "atdgen";;
#directory "/Users/michael/Workshop/rashell/src";;
#directory "/Users/michael/obj/Workshop/rashell/src";;
兩個#directory
指令對應目錄的源和目標。
(免責聲明:如果您在歷史上仔細看,你會發現,我花了一些調戲年表,但也有在那裏我繼續正是這樣其他項目 - 我只是記不準哪些)
沒有堅持ocaml;詹金斯提供了這樣做的框架。關於ocaml的tst覆蓋率:有Bisect(但基於camlp4)。 –
詹金斯不適用於TDD,它是一個持續集成引擎以及廚房水槽......編輯的問題更精確。 – insitu