我觉得一切都是冠军,但我是专门找:如何在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