Skip to content

redink/learn_exunit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

LearnExunit

entrance

1.0 start

# test/test_helper.exs
ExUnit.start()

Mix will load the test_helper.exs file before executing the tests.

cases

2.0 options

use ExUnit.Case, async: true

:async - configures tests in this module to run concurrently with tests in other modules. Tests in the same module do not run concurrently. It should be enabled only if tests do not change any global state. Defaults to false.

2.1 test macro

without context

test "true is equal to true" do
  assert true == true
end

2.2 context

All tests receive a context as an argument. There are some ways to build the context before run all test cases in individual test module.

with context

  test "unit test case with context", context do
    IO.inspect(context, label: "The context is:")
    assert true
  end

2.3 tags

  • timeout
  • capture_log
  • user-defined tag

2.4 Log Capture

This default can be overridden by @tag capture_log: false or @moduletag capture_log: false.

assertions

3.1 assert

  test "unit test assert" do
    assert true
    assert 1
    assert ""
    assert !nil
    assert !false
    assert %{} = %{a: :a, b: :b}
    assert %{} != %{a: :a, b: :b}
  end

3.2 assert_raise

  test "unit test assert_raise" do
    assert_raise ArithmeticError, "bad argument in arithmetic expression", fn -> 1 + :a end
    assert_raise RuntimeError, fn -> raise "oops" end
  end

3.3 assert_receive(d)

  test "unit test assert_receive" do
    main_pid = self()
    spawn(fn ->
      Process.sleep(1_000)
      send(main_pid, {:ok, self()})
    end)
    assert_receive {:ok, _}, 2_000
  end

  test "unit test assert_received" do
    send(self(), {:ok, self()})
    assert_received {:ok, _}
  end

3.4 catch_*

exit/throw

  test "unit test assertions catch_*" do
    assert catch_exit(exit 1) == 1
    assert catch_throw(throw 1) == 1
  end

Something about error raising exceptions in EVM

3.5 refute

  test "unit test refute" do
    refute nil
    refute false
  end

callbacks

There are many usual callbacks for ExUnit:

  • setup
  • setup_all
  • on_exit
  • start_supervised
  • stop_supervised

4.0 purpose

Build context for test case.

  test "unit test case with context", context do
    IO.inspect(context, label: "The context is:")
    assert true
  end

The context is a map, can be used in each test case.

4.1 setup

  • Optionally receive a map with test state and metadata.
  • All setup callbacks are run before each test.
  • Return keyword list/map/{:ok, keywords | map}/:ok.
  setup do
    # IO.puts("Generate random number 1 in setup")
    [random_num_1: Enum.random(1..1_000)]
  end
  setup :generate_random_number_2

  defp generate_random_number_2(context) do
    # IO.puts("Generate random number 2 in setup")
    context
    |> Map.put(:random_num_2, Enum.random(1..1_000))
  end

  test "setup case 1", %{random_num_1: random_num_1, random_num_2: random_num_2} = _context do
    IO.puts("The random numbers in case #1 are: {#{random_num_1}, #{random_num_2}}")
    assert true
  end

  test "setup case 2", %{random_num_1: random_num_1, random_num_2: random_num_2} = _context do
    IO.puts("The random numbers in case #2 are: {#{random_num_1}, #{random_num_2}}")
    assert true
  end

4.2 setup_all

  • Optionally receive a map with test state and metadata.
  • Return keyword list/map/{:ok, keywords | map}/:ok.
  • Invoked only once per module.
  setup_all do
    [setup_all_random_num_1: Enum.random(1..1_000)]
  end

  setup_all :generate_setup_all_random_number_2

  defp generate_setup_all_random_number_2(context) do
    context
    |> Map.put(:setup_all_random_num_2, Enum.random(1..1_000))
  end

  test "setup_all case 1", %{setup_all_random_num_1: num_1, setup_all_random_num_2: num_2} do
    IO.puts("The random numbers in case setup_all #1 are: {#{num_1}, #{num_2}}")
  end

  test "setup_all case 2", %{setup_all_random_num_1: num_1, setup_all_random_num_2: num_2} do
    IO.puts("The random numbers in case setup_all #2 are: {#{num_1}, #{num_2}}")
  end

mock

using mock library

5.1 mock one module with test

  test "unit test mock with one mocked module" do
    with_mock(ModuleA, cross_gwf: fn -> :ok end, kill_gwf: fn _ -> true end) do
      assert :ok == ModuleA.cross_gwf()
      assert true == ModuleA.kill_gwf(nil)
    end
  end

5.2 mock one module with test_with_mock

  test_with_mock "unit test mock using macro test_with_mock", ModuleA, [],
    cross_gwf: fn -> :ok end,
    kill_gwf: fn _ -> true end do
    assert :ok == ModuleA.cross_gwf()
    assert true == ModuleA.kill_gwf(nil)
  end

5.3 mock multi-mocked modules

  test "unit test mock with multi-mocked modules" do
    with_mocks([
      {ModuleA, [], [cross_gwf: fn -> :ok end, kill_gwf: fn _ -> true end]},
      {ModuleB, [], [cross_gwf: fn -> :ok end, kill_gwf: fn _ -> true end]}
    ]) do
      assert :ok == ModuleA.cross_gwf()
      assert true == ModuleA.kill_gwf(nil)
      assert :ok == ModuleB.cross_gwf()
      assert true == ModuleB.kill_gwf(nil)
    end
  end

5.4 use callback setup_with_mocks

  setup_with_mocks([
    {ModuleA, [], [cross_gwf: fn -> 1 end, kill_gwf: fn _ -> 2 end]},
    {ModuleB, [], [cross_gwf: fn -> 1 end, kill_gwf: fn _ -> 2 end]}
  ]) do
    :ok
  end

  test "unit test mock use setup with setup with mocks modulea" do
    assert 1 == ModuleA.cross_gwf()
    assert 2 == ModuleA.kill_gwf(nil)
  end

  test "unit test mock use setup with setup with mocks moduleb" do
    assert 1 == ModuleB.cross_gwf()
    assert 2 == ModuleB.kill_gwf(nil)
  end

reversed to codes

  test "unit test for reversed to codes" do
    assert :"1" == LearnExunit.to_to_atom(build_params_for_func("1"))
    assert :a == LearnExunit.to_to_atom(build_params_for_func("a"))

    assert :"1" == LearnExunit.to_atom("1")
    assert :a == LearnExunit.to_atom("a")
  end

coverage

Elixir coverage library

treat test cases code seriously

About

Some cases to learn for Elixir unit test

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages