Skip to content

Mimic.expect/4 silently fails when mocking a function run with Task.Supervisor.start_child/3 #109

@pablocostass

Description

@pablocostass

Summary

If you have an error (e.g.: an assert that failed) inside a Mimic.expect/4 call that happens to mock a function being run with Task.Supervisor.start_child/3, Mimic will silently fail and the test will pass, whereas if the same error happens in any other context, the erorr gets properly raised.

# let's say we have this functio
def identity(x) do
  x
end
# and this code snippet is in a test
{:ok, _pid} = Task.Supervisor.start_link(name: MyApp.TaskSupervisor)
x = 1

Mimic.expect(Mod3, :identity, fn received_x ->
  assert received_x == 2
  received_x
end)

Task.Supervisor.start_child(MyApp.TaskSupervisor, fn -> Mod3.identity(x) end)

I suppose this is due to the fact that Task.Supervisor.start_child/2 works in a fire-and-forget kind of way but I just wanted to double check if this is intended behavior, and if anyone has sensible suggestions to catch these silent errors in tests – as a workaround, for now we are sending messages after the assertions and assert_receiving them.

Environment

$ elixir --version
Erlang/OTP 27 [erts-15.2.2] [source] [64-bit] [smp:12:12] [ds:12:12:10] [async-threads:1] [jit]

Elixir 1.19.1 (compiled with Erlang/OTP 27)

Steps to reproduce

I created a small repo that exemplifies the issue https://github.com/pablocostass/mimic_minimal_examples

Clone it, and run the tests in the second describe block with

$ mix test test/mimic_issues_test.exs:31
Running ExUnit with seed: 764641, max_cases: 24
Excluding tags: [:test]
Including tags: [location: {"test/mimic_issues_test.exs", 31}]


13:23:01.797 [error] Task #PID<0.196.0> started from #PID<0.192.0> terminating
** (ExUnit.AssertionError)

Assertion with == failed
code:  assert received_x == 2
left:  1
right: 2

    (ex_unit 1.19.1) lib/ex_unit/assertions.ex:454: ExUnit.Assertions.assert/2
    test/mimic_issues_test.exs:47: anonymous fn/1 in MimicIssuesTest."test regular process vs. Task vs. Task.Supervisor properly fails with Task.async/1"/1
    (elixir 1.19.1) lib/task/supervised.ex:105: Task.Supervised.invoke_mfa/2
    (elixir 1.19.1) lib/task/supervised.ex:40: Task.Supervised.reply/4
Function: #Function<6.36367260/0 in MimicIssuesTest."test regular process vs. Task vs. Task.Supervisor properly fails with Task.async/1"/1>
    Args: []


  1) test regular process vs. Task vs. Task.Supervisor properly fails with Task.async/1 (MimicIssuesTest)
     test/mimic_issues_test.exs:43
     ** (EXIT from #PID<0.192.0>) an exception was raised:

          Assertion with == failed
          code:  assert received_x == 2
          left:  1
          right: 2
          stacktrace:
            (ex_unit 1.19.1) lib/ex_unit/assertions.ex:454: ExUnit.Assertions.assert/2
            test/mimic_issues_test.exs:47: anonymous fn/1 in MimicIssuesTest."test regular process vs. Task vs. Task.Supervisor properly fails with Task.async/1"/1
            (elixir 1.19.1) lib/task/supervised.ex:105: Task.Supervised.invoke_mfa/2
            (elixir 1.19.1) lib/task/supervised.ex:40: Task.Supervised.reply/4




  2) test regular process vs. Task vs. Task.Supervisor properly fails when not in a Task (MimicIssuesTest)
     test/mimic_issues_test.exs:32
     Assertion with == failed
     code:  assert received_x == 2
     left:  1
     right: 2
     stacktrace:
       test/mimic_issues_test.exs:36: anonymous fn/1 in MimicIssuesTest."test regular process vs. Task vs. Task.Supervisor properly fails when not in a Task"/1
       test/mimic_issues_test.exs:40: (test)

.
Finished in 0.02 seconds (0.00s async, 0.02s sync)
3 tests, 2 failures (2 excluded)

The last test passes, even though it should fail as the others.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions