basilisp.test

Basilisp automated testing framework.

The functions and macros in this namespace are useful in defining automated tests for your Basilisp code. Basilisp’s builtin test runner is a plugin for PyTest and benefits from many PyTest features such as test collection and subsetting.

Test namespaces should generally be placed in a tests directory in the root of your project. Tests may be organized into single namespaces or nested namespaces. All test namespace files should be named test_*.lpy or *_test.lpy to be eligible for collection by the test runner.

Tests within each test namespace should be wrapped in an outer deftest form and may optionally be organized within each form with testing forms. is and are may be used for making test assertions. All assertions will be processed in order to the end and all failures and errors will be reported at once.

Tests may take advantage of Basilisp fixtures via use-fixtures to perform setup and teardown functions for each test or namespace. Fixtures are not the same (nor are they compatible with) PyTest fixtures.

dynamic Var *test-failures*
dynamic Var *test-name*
dynamic Var *test-section*
macro (are argv expr & args)

Generate assertions using the template expression expr. Template expressions should be defined in terms of the symbols in the argument vector argv.

Arguments will be partitioned into groups of as many arguments are in argv and applied to the template expression.

As an example:

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

This would macroexpand to create a group of assertions like this:

(do
  (is (= 3 (+ 1 2)))
  (is (= 4 (+ 2 2)))
  (is (= 0 (+ -1 1))))

This may be convenient for generating large numbers of identically formed assertions with different arguments.

Note that assertions generated with are typically lose line numbers in test failure reports, due to the nature of the macro generation.

are assertions must appear inside of a deftest form.

macro (deftest name-sym & body)

Define a new test.

Assertions can be made with the is and are macros. Group tests with the testing macro.

Tests defined by deftest will be run by default by the PyTest test runner using Basilisp’s builtin PyTest hook.

multi fn (gen-assert expr msg line-num)

Implementation detail of is for generating macros.

macro (is expr)
macro (is expr msg)

Assert that a test condition, expr, is true. is assertion failures are recorded and reported as test failures, causing the entire containing deftest to be marked as failed.

expr can take multiple forms:

  • (is (= expected actual)) generates a basic assertion that expected and actual are equal by =; error messaging will reflect that the first element is the expected value and the second element is the actual value

  • (is (thrown? ExceptionType expr)) generates a basic assertion that expr does generate an exception of the type ExceptionType

  • (is (thrown-with-msg? ExceptionType pattern expr)) generates a basic assertion that expr does generate an exception of the type ExceptionType and that the stringified exception (as by python/str) matches the regular expression pattern using re-find

  • (is expr) is the most basic assertion type that just asserts that expr is truthy

is assertions must appear inside of a deftest form.

macro (testing msg & body)

Wrapper for test cases to provide additional messaging and context around the test or group of tests contained inside. The value of msg will be shown in the report with any test failures that occur inside this block.

testing macros may be nested. Each nested block message will be appended to the message from the previous block.

testing forms must appear inside of a deftest form.

multi fn (use-fixtures fixture-type & fixtures)

Configure fixture functions to be run for each test or once per namespace.

fixture-type may be one of:

  • :each to specify that a fixture should be run before each test

  • :once to specify that a fixture should be run once per test namespace

Fixture functions are functions of 0 arguments which must either return a value or temporarily yield control back to the test runner after performing some setup. If the yield approach is taken, the test runner will return control to the fixture whenever the test or tests have finished executing.

For example, to define a fixture with setup and teardown functions, your fixture may take this form:

(fn fixture []
  (setup-test)
  (yield)
  (teardown-test))

Fixtures will be run in the order they are provided.

Subsequent calls to use-fixtures in the same test namespace will overwrite fixtures applied during previous calls for the same fixture-type.

Note that due to the way fixtures are applied, the set of fixtures that are active for each fixture-type after all tests are collected will be applied to all tests. It is not possible to apply specific fixtures to individual tests by adding fixtures via use-fixture and then removing them after the test is defined.