Testing

Basilisp includes a PyTest plugin which supports running tests defined using the functions and macros in basilisp.test. Tests should be located in a tests/ directory off of the project root, as outlined in Project Structure. Basilisp test files should end with an .lpy suffix and the file basename should either be prefixed with test_ or suffixed with _test. Tests can be executed using the CLI or can be run directly using PyTest’s provided CLI.

Note

Basilisp supports executing both Basilisp and Python tests in the same test suite, so long as the Python tests are written using PyTest.

Tests can be written by wrapping your logic and assertions in a deftest form. Basic test assertions are written using the is macro. Tests within a deftest can be wrapped in an testing macro to both document the test function and to provide more informative testing output when tests fail. For asserting repeatedly against different inputs, you can use the are templating function.

(ns my-project.test-core
 (:require [basilisp.test :refer [deftest is are testing]]))

(deftest my-test
  (is true)

  (testing "false is really false"
    (is (not false))))

(deftest test-adding
  (are [res x y] (= res (+ x y))
    3  1 2
    4  2 2
    0 -1 1)

Fixtures

Basilisp supports test fixtures which can serve as setup and teardown functions for either individual tests or for whole test modules. Fixtures can be applied using the use-fixtures function.

Basilisp comes with one builtin fixture, which can generate a temporary directory for the duration of the test.

(ns my-project.test-core
  (:require
   [basilisp.test :as test :refer [deftest is are testing]]
   [basilisp.test.fixtures :as fixtures :refer [*tempdir*]))

(test/use-fixtures :each fixtures/tempdir)

(deftest some-test
  ;; accessing ``*tempdir*`` here will give a directory that will be
  ;; cleaned up after this test is run
  )

Fixtures can trivially be written by writing a basic function and passing it to use-fixtures. For fixtures which only need to perform setup, a fixture of no arguments will suffice. For fixtures which must perform setup and teardown or just teardown, a function of no arguments should be written and it should yield after the setup step and before the teardown. The test framework will yield control back to the fixture function when it is time to teardown.

You can see below that the fixture uses a dynamic Var to communicate what it has done back to any tests that use this fixture.

(def ^:dynamic *tempdir* nil)

(defn tempdir
  []
  (with-open [d (tempfile/TemporaryDirectory)]
    (binding [*tempdir* d]
      (yield))))

Warning

Basilisp test fixtures are not related to PyTest fixtures and they cannot be used interchangeably.