Testing
mino includes a test framework written in mino itself. It follows the same conventions as clojure.test: named tests with deftest, assertions with is, and contextual grouping with testing.
The framework is clojure.test, loaded via (require '[clojure.test :refer [deftest is testing]]) from test files. tests/test.clj is a compatibility entry point that delegates to clojure.test.
Writing Tests
A test file is a normal .clj file that requires the framework and defines tests:
(require "tests/test")
(deftest addition
(is (= 3 (+ 1 2))))
(deftest string-operations
(testing "concatenation"
(is (= "hello world" (str "hello" " " "world"))))
(testing "substring"
(is (= "ell" (subs "hello" 1 4)))))
(deftest error-handling
(is (thrown? (throw "expected error"))))API Reference
(deftest name & body)
Defines and registers a named test. The body contains one or more assertions. Tests are collected in registration order and executed when run-tests is called.
(is expr) / (is expr msg)
The core assertion macro. Returns the result of the expression. On failure, records the original form, an optional message, and expected vs. actual values.
Four assertion modes:
| Form | Passes when |
|---|---|
(is (= expected actual)) | Values are equal. Reports expected and actual on failure. |
(is (thrown? body...)) | Body throws an exception. Fails if no exception is raised. |
(is (thrown-with-msg? <re> body...)) | Body throws and the thrown value's message matches the
regex. The 4-arg JVM shape (thrown-with-msg? <Class> <re> body...) is also accepted; the class symbol is
documentation-only (mino has no class hierarchy). |
(is expr) | Expression is truthy (not nil or false). |
(testing desc & body)
Adds a context string to failure messages. Context strings nest and are joined with > in the output. Must appear inside a deftest.
(deftest collections
(testing "vectors"
(testing "equality"
(is (= [1 2 3] [1 2 3])))))
;; On failure: "vectors > equality"(run-tests)
Executes all registered tests and prints a summary. Each test runs in a try/catch so one failure does not prevent the rest from running. Calls (exit 1) on any failures or errors, (exit 0) on success.
Running Tests
# Run the test suite
./mino task test
# Run under GC stress (collects on every allocation)
MINO_GC_STRESS=1 ./mino tests/run.cljTest File Organization
By convention, test files live in tests/ and are named *_test.clj. A runner file loads all test modules and calls run-tests:
;; tests/run.clj
(require "tests/test")
(require "tests/arithmetic_test")
(require "tests/string_test")
;; ...
(run-tests)Each test file starts with (require "tests/test") to load the framework. The require call is idempotent: the framework is loaded once and cached.
Output
On success:
1474 tests, 7038 assertions: 7038 passed, 0 failed, 0 errorsOn failure, each failing assertion is reported with its test name, context path, the original form, and a diff:
Failures:
in addition
arithmetic > basic
(= 4 (+ 1 2))
expected: 4
actual: 3
10 tests, 12 assertions: 11 passed, 1 failed, 0 errorsTesting in the REPL
The test framework works in the REPL too. Load it, define a test, and call run-tests interactively:
mino> (require "test")
mino> (deftest quick-check (is (= 4 (+ 2 2))))
mino> (run-tests)
1 tests, 1 assertions: 1 passed, 0 failed, 0 errors