一键导入
testing
Testing strategies for OCaml libraries. Use when discussing tests, alcotest, eio mocks, test structure, or test-driven development in OCaml projects.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Testing strategies for OCaml libraries. Use when discussing tests, alcotest, eio mocks, test structure, or test-driven development in OCaml projects.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Working with the OxCaml extensions to OCaml. Use when the oxcaml compiler is available and you need high-performance, unboxing, stack allocation, data-race-free parallelism
OCaml 5 algebraic effects design patterns. Use when Claude needs to: (1) Design APIs that interact with effect-based schedulers, (2) Decide between effects vs exceptions, (3) Integrate libraries with Eio or affect, (4) Handle suspension vs error cases in streaming code, (5) Understand the layered effect design principle
OCaml fuzz testing with Crowbar for protocol implementations. Use when Claude needs to: (1) Write fuzz tests for parsers and encoders, (2) Test roundtrip invariants (parse(encode(x)) = x), (3) Verify boundary conditions and error handling, (4) Test state machines and transitions, (5) Organize fuzz test suites for large codebases, (6) Run long-lived AFL campaigns with Crowbar
JSON type-safe encoding and decoding using the OCaml jsont library. Use when Claude needs to: define typed JSON codecs for OCaml record types, parse JSON strings to OCaml values, or serialize OCaml values to JSON, or work with nested JSON structures
Fixing odoc documentation warnings and errors. Use when running dune build @doc, resolving reference syntax issues, cross-package references, ambiguous references, hidden fields, or @raise tags in OCaml documentation.
Standards for OCaml project metadata files. Use when initializing a new OCaml library/module, preparing for opam release, setting up CI, discussing project structure, or ensuring proper .mli/.ocamlformat files exist.
| name | testing |
| description | Testing strategies for OCaml libraries. Use when discussing tests, alcotest, eio mocks, test structure, or test-driven development in OCaml projects. |
Use test/ directory with:
test.ml - Main runner controlling initialization ordertest_x.ml - One file per module x.ml being tested, exports suitelib/
├── foo.ml
└── bar.ml
test/
├── dune
├── test.ml # Main runner
├── test_foo.ml # suite : (string * unit Alcotest.test_case list) list
└── test_bar.ml
For single-module libraries, a single test_foo.ml as runner is acceptable.
(test
(name test)
(libraries mylib alcotest logs logs.fmt fmt.tty))
The main test.ml controls initialization order for side effects:
(* 1. Initialize RNG before any test module is loaded *)
let () = Crypto_rng_unix.use_default ()
(* 2. Set up logging *)
let () = Fmt_tty.setup_std_outputs ()
let () = Logs.set_reporter (Logs_fmt.reporter ())
let () = Logs.set_level (Some Logs.Debug)
(* 3. Run all test suites *)
let () = Alcotest.run "mylib" Test_foo.suite
For multiple modules:
let () = Crypto_rng_unix.use_default ()
let () = Alcotest.run "mylib" (Test_foo.suite @ Test_bar.suite)
Each module exports a suite value. Do not initialize RNG or run Alcotest here.
(** Tests for Foo module. *)
let test_basic () =
let result = Foo.process "input" in
Alcotest.(check string) "expected output" "output" result
let test_empty () =
let result = Foo.process "" in
Alcotest.(check string) "empty input" "" result
let suite =
[
( "process",
[
Alcotest.test_case "basic" `Quick test_basic;
Alcotest.test_case "empty" `Quick test_empty;
] );
]
If a test module needs RNG at load time, use lazy evaluation:
let key = lazy (Crypto_rng.generate 32)
let key () = Lazy.force key
let test_encrypt () =
let ciphertext = Foo.encrypt ~key:(key ()) plaintext in
...
This defers RNG use until tests actually run, after test.ml initializes the RNG.
let result_testable ok_t =
Alcotest.result ok_t Alcotest.string
let my_type_testable =
Alcotest.testable My_type.pp My_type.equal
Alcotest.(check int) "count" 42 actual
Alcotest.(check string) "name" expected actual
Alcotest.(check bool) "flag" true actual
Alcotest.(check (list int)) "items" [1;2;3] actual
Alcotest.(check (option string)) "maybe" (Some "x") actual
Alcotest.(check (result int string)) "result" (Ok 42) actual
let test_raises () =
Alcotest.check_raises "should fail" (Invalid_argument "bad")
(fun () -> Foo.parse "bad")
Always initialize in test.ml before Alcotest.run:
Crypto_rng_unix.use_default () or Mirage_crypto_rng_unix.use_default ()Logs.set_reporter and Logs.set_levelThis ensures deterministic test ordering and proper side-effect sequencing.
Set up logging in tests using the standard Logs library:
let () = Fmt_tty.setup_std_outputs ()
let () = Logs.set_reporter (Logs_fmt.reporter ())
let () = Logs.set_level (Some Logs.Debug)
Default behaviour: Logs at Debug level. Alcotest captures output to a file by default, so verbose logging doesn't clutter the terminal. Output is shown only when tests fail.
For per-source control, set levels after the reporter:
let () = Logs.Src.set_level Conpool.src (Some Logs.Debug)
let () = Logs.Src.set_level Requests.src (Some Logs.Warning)
lib/ should have a corresponding test module in test/."users", "commands", "process")"basic", "empty_input", "parse_error")Function Coverage: Test all public functions exposed in .mli files, including success, error, and edge cases.
Test Data: Use helper functions to create test data:
let make_user ?(name = "test") ?(id = 1) () = User.v ~name ~id
Property-Based Testing: For complex logic, consider property-based testing with QCheck:
let test_roundtrip =
QCheck.Test.make ~count:1000
~name:"encode then decode is identity"
QCheck.string
(fun s -> Codec.decode (Codec.encode s) = s)
Cram tests verify CLI executable behavior.
Use Cram Directories: Every Cram test should be a directory ending in .t (e.g., my_feature.t/).
Create Actual Test Files: Avoid embedding code within run.t using heredocs. Create real source files within the test directory.
test/
└── my_feature.t/
├── run.t # The cram test script
├── input.txt # Test input file
└── expected.json # Expected output
# Run all tests
dune test
# Run tests and watch for changes
dune test -w
# Run a specific test
dune exec test/test.exe -- test "suite_name"
# Run tests with coverage
dune test --instrument-with bisect_ppx
bisect-ppx-report summary