ExUnit mocks get mixed up in their concurrency (async: false not working?)

555 views Asked by At

While executing ExUnit.start, in each case, I prepare mocks by meck like bellow

defmodule MyModule.FooTest do
    use ExUnit.Case, async: false # explicitly sync
    import :meck

    alias MyModule.Foo
    alias MyModule.Baz # to be mocked

    test "call_baz" do
        expect(Baz, :some_async_method, [
            {[], :meck.val(Task.async(fn -> %{"name" => "otiai10"} end)},
        ])

        assert Foo.call_baz() == %{"name" => "otiai10"}
    end
end

But it returns {"name" => "otiai200"} , because Baz.some_async_method is mocked by another test with returning {"name" => "otiai200"}.

It is certainly the response of what mocked in another test cases. (They are also given async: false option in their use statement)

What is the problem, async: false option doesn't work? or is mocking Task.async not recommended? Or do I do any basic mistakes?

Thank you

1

There are 1 answers

1
Adam Lindberg On BEST ANSWER

Meck requires explicit unloading of mocks. Therefore, it is possible that another test running in parallel will update the expectation while you are running this test. Try adding :meck.unload(Baz) in the teardown to each test using the mock.

I'm not familiar with how Elixir decides to run it's test suites (maybe in parallel, even though they are async internally?) so this might factor in. As Meck is modifying the global module namespace, you should not mock the same module in parallel from different test cases.

I'd suggest trying to use the Meck wrapper Mock for Elixir to see if this gives you the same result.