eunit a powerful unit testing framework for erlang richard carlsson mickaël rémond

39
EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

Upload: roberta-cordelia-fox

Post on 19-Jan-2016

219 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

EUnit

a powerful unit testing framework for Erlang

Richard Carlsson

Mickaël Rémond

Page 2: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

What is unit testing?

● Testing “program units” in isolation Functions, modules, subsystems

● Testing specified behaviour (contracts) Input/output Stimulus/response Preconditions/postconditions, invariants

Page 3: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

What unit testing is not

● Unit testing does not cover: Performance testing Usability testing System testing Etc.

● Unit tests do not replace, but can be an important part of: Regression testing Integration testing

Page 4: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

Test-driven design

● Write unit tests (and run them, often) while developing the program, not afterwards

● Write tests for a feature before implementing that feature

● Move on to another feature when all tests pass● Good for focus and productivity:

Concentrate on solving the right problems Avoid overspecification and premature optimization

● Regression tests for free

Page 5: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

Unit testing frameworks

● Make it easy to: Write tests

● minimal typing overhead Run tests

● at the push of a button View test results

● efficient feedback

● Made popular by the JUnit framework for Java by Beck and Gamma.

Page 6: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

Functional unit testing

● The “xUnit family” of frameworks (JUnit, etc.) are mostly built on object-oriented principles Heavy use of inheritance:

● scaffolding (code for running the tests)● setup/teardown of test contexts (open/close files, etc.)

● We want to be able to handle tests as data Lambda expressions (funs) make natural test cases Represent test sets as collections (lists) of funs Deep lists make it easy to combine test sets

Page 7: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

Test case conventions

● A test case is represented as a fun that takes no arguments

● A test fails if evaluation throws an exception● Any return value is considered a success

Test = fun () -> ... end,try Test() of _ -> okcatch _:_ -> errorend

Page 8: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

Using EUnit

● Most basic usage:eunit:test(TestSet)

● Where TestSet can be: a fun (taking zero arguments) a module name various other things (as we shall see) a (deep) list of funs, module names, and

other things

Page 9: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

Modules as test sets

● Given a module name (any atom), EUnit will look for exported functions with special names:

..._test() % simple test

..._test_() % test generator● Simple test functions are treated just as funs:

they represent a single test case.● Test generators are called immediately, and

should return a test set (a fun, module name, list of tests, etc.)

Page 10: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

Using EUnit in your code

● The hard way: Add test functions (with conforming names)

● simple test functions (one test case per function)● generator functions, returning lists of funs

Export the functions Call eunit:test(Modulename)

● Using EUnit header files makes life easier Many useful macros Some additional magic

Page 11: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

EUnit utility macros

● -include_lib(“eunit/include/eunit.hrl”).

● Make the code more compact and readable● Generate more informative exceptions

?assert(1 + 1 == 2)

?assertMatch({foo, _}, make_foo(42))

?assertError(badarith, 1/0)

?assertThrow(ouch, throw(ouch))

Page 12: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

Fun-wrapper macros

● Macros whose names begin with “_” wrap their arguments in a fun-expression:

?_test(Expr) <=> fun()-> Expr end● Most test macros have _-forms:

?_test(?assert(BoolExpr)) <=> ?_assert(BoolExpr)

● Usage comparison:

simple_test()-> ?assert(BoolExpr).

fun_test_()-> ?_assert(BoolExpr).

Page 13: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

Developing a module with EUnit

-module(fib).-export([fib/1]).

fib(0) -> 1;fib(1) -> 1;fib(N) when N > 1 -> fib(N-1) * fib(N-2).

Page 14: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

Developing a module with EUnit

-module(fib).-export([fib/1]).-include_lib(“eunit/include/eunit.hrl”).

fib(0) -> 1;fib(1) -> 1;fib(N) when N > 1 -> fib(N-1) * fib(N-2).

Page 15: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

Test functions are auto-exported

-module(fib).-export([fib/1]).-include_lib(“eunit/include/eunit.hrl”).

fib(0) -> 1;fib(1) -> 1;fib(N) when N > 1 -> fib(N-1) * fib(N-2).

fib0_test() -> ?assert(fib(0) == 1).

Page 16: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

Test functions are auto-exported

-module(fib).-export([fib/1]).-include_lib(“eunit/include/eunit.hrl”).

fib(0) -> 1;fib(1) -> 1;fib(N) when N > 1 -> fib(N-1) * fib(N-2).

fib0_test() -> ?assert(fib(0) == 1).

fib1_test() -> ?assert(fib(1) == 1).

Page 17: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

Test functions are auto-exported

-module(fib).-export([fib/1]).-include_lib(“eunit/include/eunit.hrl”).

fib(0) -> 1;fib(1) -> 1;fib(N) when N > 1 -> fib(N-1) * fib(N-2).

fib0_test() -> ?assert(fib(0) == 1).

fib1_test() -> ?assert(fib(1) == 1).

fib2_test() -> ?assert(fib(2) == 2).

Page 18: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

Compact code with generators

-module(fib).-export([fib/1]).-include_lib(“eunit/include/eunit.hrl”).

fib(0) -> 1;fib(1) -> 1;fib(N) when N > 1 -> fib(N-1) * fib(N-2).

fib_test_() ->[?_assert(fib(0) == 1), ?_assert(fib(1) == 1), ?_assert(fib(2) == 2)].

Page 19: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

Compact code with generators

-module(fib).-export([fib/1]).-include_lib(“eunit/include/eunit.hrl”).

fib(0) -> 1;fib(1) -> 1;fib(N) when N > 1 -> fib(N-1) * fib(N-2).

fib_test_() ->[?_assert(fib(0) == 1), ?_assert(fib(1) == 1), ?_assert(fib(2) == 2), ?_assert(fib(3) == 3), ?_assert(fib(4) == 5), ?_assert(fib(5) == 8)].

Page 20: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

Also test the error cases

-module(fib).-export([fib/1]).-include_lib(“eunit/include/eunit.hrl”).

fib(0) -> 1;fib(1) -> 1;fib(N) when N > 1 -> fib(N-1) * fib(N-2).

fib_test_() ->[?_assert(fib(0) == 1), ?_assert(fib(1) == 1), ?_assert(fib(2) == 2), ?_assert(fib(3) == 3), ?_assert(fib(4) == 5), ?_assert(fib(5) == 8), ?_assertError(function_clause, fib(-1))].

Page 21: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

Compiling and running

1> c(fib).

Page 22: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

Compiling and running

1> c(fib).{ok,fib}2>

Page 23: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

Compiling and running

1> c(fib).{ok,fib}2> eunit:test(fib).

Page 24: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

Reading error reports

1> c(fib).{ok,fib}2> eunit:test(fib).fib:12:fib_test_...*failed*::{error,{assertion_failed, [{module, fib}, {line,12, {expression, “fib ( 2 ) == 2”}, {expected, true}, {value, false}]},...================================================= Failed: 4 Aborted: 0 Skipped: 0 Succeeded: 33>

Page 25: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

Fixing errors

-module(fib).-export([fib/1]).-include_lib(“eunit/include/eunit.hrl”).

fib(0) -> 1;fib(1) -> 1;fib(N) when N > 1 -> fib(N-1) * fib(N-2).

fib_test() ->[?_assert(fib(0) == 1), ?_assert(fib(1) == 1), ?_assert(fib(2) == 2), ?_assert(fib(3) == 3), ?_assert(fib(4) == 5), ?_assert(fib(5) == 8), ?_assertError(function_clause, fib(-1))].

Page 26: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

Fixing errors

-module(fib).-export([fib/1]).-include_lib(“eunit/include/eunit.hrl”).

fib(0) -> 1;fib(1) -> 1;fib(N) when N > 1 -> fib(N-1) + fib(N-2).

fib_test() ->[?_assert(fib(0) == 1), ?_assert(fib(1) == 1), ?_assert(fib(2) == 2), ?_assert(fib(3) == 3), ?_assert(fib(4) == 5), ?_assert(fib(5) == 8), ?_assertError(function_clause, fib(-1))].

Page 27: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

Using the automatic test() function

3> c(fib).{ok,fib}4> fib:test().

Page 28: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

Using the automatic test() function

3> c(fib).{ok,fib}4> fib:test(). All 7 tests successfulok5>

Page 29: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

Advanced test descriptors

● Labels{“Label Text”, Tests}

Page 30: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

Advanced test descriptors

● Labels{“Label Text”, Tests}

● Timeouts{timeout, Seconds, Tests}

Page 31: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

Advanced test descriptors

● Labels{“Label Text”, Tests}

● Timeouts{timeout, Seconds, Tests}

● Running tests in subprocesses{spawn, Tests}

Page 32: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

Advanced test descriptors

● Labels{“Label Text”, Tests}

● Timeouts{timeout, Seconds, Tests}

● Running tests in subprocesses{spawn, Tests}{spawn, Node, Tests}

Page 33: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

Advanced test descriptors

● Labels{“Label Text”, Tests}

● Timeouts{timeout, Seconds, Tests}

● Running tests in subprocesses{spawn, Tests}{spawn, Node, Tests}

● Specifying the execution order{inparallel, Tests}

Page 34: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

Advanced test descriptors

● Labels{“Label Text”, Tests}

● Timeouts{timeout, Seconds, Tests}

● Running tests in subprocesses{spawn, Tests}{spawn, Node, Tests}

● Specifying the execution order{inparallel, Tests}{inorder, Tests}

Page 35: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

More advanced test descriptors

● Running system commands{cmd, “Command String”}

Page 36: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

More advanced test descriptors

● Running system commands{cmd, “Command String”}

● Generators{generator, Fun}{generator, Module, Function}

Page 37: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

More advanced test descriptors

● Running system commands{cmd, “Command String”}

● Generators{generator, Fun}{generator, Module, Function}

● Test setup and cleanup{setup, SetupFun, % () -> R::any() CleanupFun, % (R::any()) -> any() (Instantiator % (R::any()) -> Tests | Tests)}

(setup runs the tests in a new process by default)

Page 38: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

And some even more advanced

● Repeated setup and cleanup{foreach, SetupFun, CleanupFun, [ Instantiator|Tests ]}

{foreachx, SetupFunX, CleanupFunX, [ {X::any(), InstantiatorX|Tests} ]

Page 39: EUnit a powerful unit testing framework for Erlang Richard Carlsson Mickaël Rémond

End