W3cubDocs

/Elixir 1.5

ExUnit.Callbacks

Defines ExUnit callbacks.

This module defines both setup_all and setup callbacks, as well as the on_exit/2, start_supervised/2 and stop_supervised/1 functions.

The setup callbacks are defined via macros and each one can optionally receive a map with metadata, usually referred to as context. The callback may optionally put extra data into the context to be used in the tests.

The setup_all callbacks are invoked only once per module, before any test runs. All setup callbacks are run before each test. No callback runs if the test case has no tests or all tests have been filtered out.

start_supervised/2 is used to start processes under a supervisor. The supervisor is linked to the current test process. The supervisor as well as all child processes are guaranteed to terminate before any on_exit/2 callback runs.

on_exit/2 callbacks are registered on demand, usually to undo an action performed by a setup callback. on_exit/2 may also take a reference, allowing callback to be overridden in the future. A registered on_exit/2 callback always runs, while failures in setup and setup_all will stop all remaining setup callbacks from executing.

Finally, setup_all callbacks run in a separate process per module, while all setup callbacks run in the same process as the test itself. on_exit/2 callbacks always run in a separate process, as implied by their name. The test process always exits with reason :shutdown, which means any process linked to the test process will also exit, although asynchronously. Therefore it is preferred to use start_supervised/2 to guarantee synchronous termination.

Here is a run down of the life-cycle of the test process:

  1. the test process is spawned
  2. it runs setup/2 callbacks
  3. it runs the test itself
  4. it stops all supervised processes
  5. the test process exits with reason :shutdown
  6. on_exit/2 callbacks are executed in a separate process

Context

If you return a keyword list, a map, or {:ok, keywords | map} from setup_all, the keyword list/map will be merged into the current context and be available in all subsequent setup_all, setup, and the test itself.

Similarly, returning a keyword list, map, or {:ok, keywords | map} from setup means that the returned keyword list/map will be merged into the current context and be available in all subsequent setup and the test itself.

Returning :ok leaves the context unchanged (both in setup and setup_all callbacks).

Returning anything else from setup_all will force all tests to fail, while a bad response from setup causes the current test to fail.

Examples

defmodule AssertionTest do
  use ExUnit.Case, async: true

  # "setup_all" is called once per module before any test runs
  setup_all do
    IO.puts "Starting AssertionTest"

    # No context is returned here
    :ok
  end

  # "setup" is called before each test
  setup do
    IO.puts "This is a setup callback for #{inspect self()}"

    on_exit fn ->
      IO.puts "This is invoked once the test is done. Process: #{inspect self()}"
    end

    # Returns extra metadata to be merged into context
    [hello: "world"]
  end

  # Same as above, but receives the context as argument
  setup context do
    IO.puts "Setting up: #{context.test}"
    :ok
  end

  # Setups can also invoke a local or imported function that returns a context
  setup :invoke_local_or_imported_function

  test "always pass" do
    assert true
  end

  test "uses metadata from setup", context do
    assert context[:hello] == "world"
  end

  defp invoke_local_or_imported_function(context) do
    [from_named_setup: true]
  end
end

Summary

Functions

on_exit(name_or_ref \\ make_ref(), callback)

Defines a callback that runs once the test exits

setup(block)

Defines a callback to be run before each test in a case

setup(var, block)

Defines a callback to be run before each test in a case

setup_all(block)

Defines a callback to be run before all tests in a case

setup_all(var, block)

Defines a callback to be run before all tests in a case

start_supervised(child_spec_or_module, opts \\ [])

Starts a child process under the test supervisor

stop_supervised(id)

Stops a child process started via start_supervised/2

Functions

on_exit(name_or_ref \\ make_ref(), callback)

on_exit(term, (() -> term)) :: :ok | no_return

Defines a callback that runs once the test exits.

callback is a function that receives no arguments and runs in a separate process than the caller.

on_exit/2 is usually called from setup and setup_all callbacks, often to undo the action performed during setup. However, on_exit/2 may also be called dynamically, where a reference can be used to guarantee the callback will be invoked only once.

setup(block) (macro)

Defines a callback to be run before each test in a case.

Examples

setup :clean_up_tmp_directory

setup(var, block) (macro)

Defines a callback to be run before each test in a case.

Examples

setup context do
  [conn: Plug.Conn.build_conn()]
end

setup_all(block) (macro)

Defines a callback to be run before all tests in a case.

Examples

setup_all :clean_up_tmp_directory

setup_all(var, block) (macro)

Defines a callback to be run before all tests in a case.

Examples

setup_all context do
  [conn: Plug.Conn.build_conn()]
end

start_supervised(child_spec_or_module, opts \\ [])

start_supervised(Supervisor.child_spec | module | {module, term}, keyword) :: Supervisor.on_start_child

Starts a child process under the test supervisor.

It expects a child specification or a module, similar to the ones given to Supervisor.start_link/2. For example, if your application starts a supervision tree by running:

Supervisor.start_link([MyServer, {OtherSupervisor, ...}], ...)

You can start those processes under test in isolation by running:

start_supervised(MyServer)
start_supervised({OtherSupervisor, :initial_value})

A keyword list can also be given if there is a need to change the child specification for the given child process:

start_supervised({MyServer, :initial_value}, restart: :temporary)

See the Supervisor module for a discussion on child specifications and the available specification keys.

The advantage of starting a process under the test supervisor is that it is guaranteed to exit before the next test starts. Furthermore, because the child process is supervised, it will be restarted in case of crashes according to the :restart strategy in the child specification, even if stopped manually. Therefore, to guarantee a process started with start_supervised/2 terminates without restarts, see stop_supervised/1.

This function returns {:ok, pid} in case of success, otherwise it returns {:error, reason}.

stop_supervised(id)

stop_supervised(id :: term) :: :ok | {:error, :not_found}

Stops a child process started via start_supervised/2.

This function expects the id in the child specification. For example:

{:ok, _} = start_supervised(MyServer)
:ok = stop_supervised(MyServer)

It returns :ok if there is a supervised process with such id, {:error, :not_found} otherwise.

© 2012–2017 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/ex_unit/1.5.0/ExUnit.Callbacks.html