This project has been deprecated in favor of ltest (which has 100% inherited from lfeunit).
Caveat Emptor: This is a new project with some implementation done. Patches welcome!
The original implementation of lfeunit was made due to some difficulties in
parsing the eunit.hrl
file fully by LFE (it didn't convert all the Erlang
macros). Robert has since made some enhancements to the LFE Erlang macro
processing code, and it now pulls in everything.
Is there still a need for lfeunit?
Well, perhaps not need, but certainly a benefit :-) lfeunit is intended to be more Lisp-y than simply calling macros from eunit. Futhermore, we hope to define some macros that will make testing a pleasure in LFE.
(deftest ...)
for standard unit tests(deftestgen ...)
for writing tests with generators, including the standard EUnit test fixtures (see naming caveat below)(deftestskip ...)
for skipping unit tests(list ...)
-wrapped tests (of arbitrary depth) for use as test sets(tuple ...)
-wrapped tests for naming/describing tests (first element of tuple)
With version 0.1.0, lfeunit changed its API. Functions were converted to macros,
and these were renamed from assert-*
to is-*
.
If you have projects that are still using either the previous release (0.0.1) or
old development snapshots and you want to continue using these, you can update
your rebar.config
to point to "old-style" instead of "master", for example:
{deps, [
{lfe, ".*", {git, "git://github.com/rvirding/lfe.git", "develop"}},
{lfeunit, ".*", {git, "git://github.com/lfe/lfeunit.git", "old-style"}}
]}.
lfeunit
writes its unit tests in lfeunit
:-) You can run them from the
project directory:
$ make check
Which will give you output similar to the following:
------------------
Running unit tests ...
------------------
======================== EUnit ========================
unit-check2-tests: basic2-test- ...[ok]
module 'unit-lfeunit-fixture-tests'
setup-test-case ................................ [ok]
setup-test-case ................................ [ok]
setup-test-case ................................ [ok]
setup-test-case ................................ [ok]
setup-test-case ................................ [ok]
setup-test-case ................................ [ok]
foreach-test-case .............................. [ok]
foreach-test-case .............................. [ok]
setup-test-case ................................ [ok]
setup-test-case ................................ [ok]
foreach-test-case .............................. [ok]
foreach-test-case .............................. [ok]
Total module test time: 0.036 s
module 'unit-lfeunit-generated-tests'
one-lambda ..................................... [ok]
one-lambda-in-list ............................. [ok]
many-lambdas-in-list ........................... [ok]
many-lambdas-in-list ........................... [ok]
many-lambdas-in-list ........................... [ok]
lambda-with-nested-testset ..................... [ok]
Total module test time: 0.018 s
module 'unit-lfeunit-named-tests'
named-is ....................................... [ok]
named-is-not-fail .................... [0.003 s] [ok]
named-testset-with-one ......................... [ok]
named-testset-with-two ......................... [ok]
named-testset-with-three ....................... [ok]
named-testset-nested ........................... [ok]
named-testset-deeply-nested .................... [ok]
Total module test time: 0.024 s
module 'unit-lfeunit-tests'
is ............................................. [ok]
is-with-one-phrase-deftest ..................... [ok]
is-with-two-phrase-deftest ..................... [ok]
is-with-many-phrase-deftest .................... [ok]
is-fail ........................................ [ok]
is-not ......................................... [ok]
is-not-fail .................................... [ok]
is-equal ....................................... [ok]
is-equal-fail .................................. [ok]
is-not-equal ................................... [ok]
is-not-equal-fail .............................. [ok]
is-exception ................................... [ok]
is-exception-wrong-class ....................... [ok]
is-exception-wrong-term ........................ [ok]
is-exception-unexpected-success ................ [ok]
is-error ....................................... [ok]
is-error-wrong-term ............................ [ok]
is-error-unexpected-success .................... [ok]
is-throw ....................................... [ok]
is-throw-wrong-term ............................ [ok]
is-throw-unexpected-success .................... [ok]
is-exit ........................................ [ok]
is-exit-wrong-term ............................. [ok]
is-exit-unexpected-success ..................... [ok]
is-match ....................................... [ok]
is-match-fail .................................. [ok]
Total module test time: 0.078 s
module 'unit-lfeunit-testset-tests'
testset-with-one ............................... [ok]
testset-with-two ............................... [ok]
testset-with-three ............................. [ok]
testset-nested ................................. [ok]
testset-deeply-nested .......................... [ok]
Total module test time: 0.016 s
=======================================================
All 57 tests passed.
In order to use lfeunit in your project, all you need to do is add a Rebar dep.
In your rebar.config
file, simply add an extra line for lfeunit
:
{deps, [
{lfe, ".*", {git, "git://github.com/rvirding/lfe.git", "develop"}},
{lfeunit, ".*", {git, "git://github.com/lfe/lfeunit.git", "master"}}
]}.
Once you write some tests (see below for how to do that), you can then do this:
$ lfetool tests build
$ lfetool tests unit
We recommend not putting your unit tests directly in your modules, but rather
creating a top-level directory in your project called test
. In test
,
create a test cases module for every module your project has, e.g.,
test/myproj-base-tests.lfe
and test/myproj-util-tests.lfe
. Obviously,
if it makes sense to break things up in a more fine-grained manner, feel free
to do so :-)
Furthermore, LFE projects support a standard directory layout for separating
unit, integration, and system tests. These are written as modules in their own
directories, but compiled to the standard .eunit
directory. Modules of a
particular type (e.g., unit, integration, etc.) are distinguished by a module
name prefix.
For a working example of such a structure, see the layout of the lfeunit
project itself: it uses just such a setup.
Keep in mind that your tests will be compiled to .beam
and then run with
Erlang's eunit module. As such, your tests need to following the same
conventions that eunit establishes:
- Test module filenames should end in
-tests
, e.g.,some-module-tests.lfe
. (In older versions of LFE, it may have been required to name test module filenames with_tests
, however this is no longer the case.) - Test module and filename need to be the same, minus the extension. For
example,
test/unit/unit-my-module-tests.lfe
needs to be declared as(defmodule unit-my-module-tests ...) in the test case module
. - If you chose not to use the
deftest
macro to build each unit test function, you will need to name your unit test functions with_test
appended to them. For example,(defun unit-my-function-negagive-check_test () ...)
. We recommend, however, that you usedeftest
instead, and obviate the need for_test ()
boilerplate.
Naming rules with fixtures: If you choose to use named functions instead of ``lambda``s for your fixtures or if your ``lambda``s make calls to functions -- all of those need to be standard, unquoted Erlang atoms. In otherwords: no dashes; you must use underscores.
lfeunit is entirely macro-based. lfeunit uses LFE to parse the Erlang macros in the eunit header file. It also provides its own header file which defines macros whose purpose is to wrap the eunit macros in a more Lispy form.
lfeunit also provides a syntactic sugar macro for defining tests: deftest
.
Instead of writing something like this for your unit tests:
(defun unit-my-function-test ()
...)
You can use deftest
to write this:
(deftest unit-my-function
...)
Note that the -test
is no longer needed, nor is the empty argument list.
If you would like to use EUnit's fixtures feature, you must use another macro:
(deftestgen unit-my-function
...)
See above the note on naming functions for use in fixtures.
If you would like tests to be skipped, you can use this macro:
(deftestskip unit-my-function
...)
This will simply make the test invisible to EUnit. EUnit doesn't actually track user-skipped tests; it only tracks tests that are skipped do to issues as perceived by EUnit.
Here is a more complete example:
(defmodule unit-mymodule-tests
(export all)
(import
(from lfeunit-util
(check-failed-assert 2)
(check-wrong-assert-exception 2))))
(include-lib "deps/lfeunit/include/lfeunit-macros.lfe")
(deftest is
(is 'true)
(is (not 'false))
(is (not (not 'true))))
(deftest is-not
(is-not `'false))
(deftest is-equal
(is-equal 2 (+ 1 1)))
lfeunit is working towards full test coverage; while not there yet, the unit tests for lfeunit itself provide the best examples of usage.
Rebar doesn't seem to compile lfe unit tests right now (See the
Rebar discussion for more information about this). As such, we have to do a
little more work. Prior to lfetool
each project had to include make
targets for compiling unit tests. lfetool
now does this for you. Running
tests is now as easy as doing the following:
$ lfetool tests build
$ lfetool tests unit
or
$ lfetool tests all
If you would like to see how to do this manually, you should examine the source
code of lfetool
. In particular, the file
plugins/lfetool/templates/lfetool.tmpl
in the lfetool source code.
Also, for an example of testing targets that are using lfetool
, see the
`common.mk`_ file for this project.
Once your project is using these targets, you can simply execute the any one of the following to run your tests:
$ make check
$ make check-unit-only
$ make check-integration-only
$ make check-system-only
$ make check-unit-with-deps
$ make check-unit
$ make check-integration
$ make check-system
$ make check-all-with-deps
$ make check-all
The make targets suffixed with -only
assume that your unit tests have
already been compiled (as such, these run very quickly). The other targets do
various levels of compiling (deps, tests, etc.) for you, at which point your
.lfe
test files will be compiled to .beam
and placed in the testing
directory (.eunit
). This is the directory that all check*
targets
use to look for the tests to run.