View Source Multiverses (multiverses v0.11.0)
Elixir introduces into the world of programming, the "multiverse testing" pattern. This is a pattern where integration tests are run concurrently and each test sees a shard of global state.
pre-existing-examples
Pre-Existing Examples:
Mox
: each test has access to the global module mock, sharded by the pid of the running test.Ecto
: each test has access to a "database sandbox", which is a checked out transaction on the global database that acts as its own database shard.Hound
,Wallaby
: each test generates an ID that is passed outside of the BEAM that is reintercepted on ingress, this ID is then used to connect ecto sandboxes to the parent test PID
This library implements Multiverses-aware versions of several constructs in the Elixir Standard Library that aren't natively Multiversable.
For plugins that are provided for other systems, see the libraries:
:multiverses_http
- which extends this to HTTP requests that exit the BEAM.:multiverses_pubsub
- which extends this to Phoenix.PubSub
The following multiverse modules are provided by this core package:
Multiverses.Application
- which shards the application environment variablesMultiverses.Registry
- which shards Registries
usage
Usage
In mix.exs
, add the following dependency:
{:multiverses, "~> 0.11.0", only: :test}
in-your-code
In your code
For example, if you would like to use the Multiverses
version of the Application
module (Multiverses.Application
), add the following lines:
To config/config.exs
:
config :my_app, Application, Application
To config/test.exs
:
config :my_app, Application, Multiverses.Application
To the module where you would like to use multiverses Application
:
@application Application.compile_env(:my_app, Application)
And where you would like to make a multiverses Application call:
def some_function do
value = @application.get_env(:my_app, :some_env_variable)
# ...
end
in-your-tests
In your tests
- Register the module you'd like to substitute with multiverses.
setup do
Multiverses.shard(Application)
end
- Your tests have segregated application values!
defmodule MyModule do
@application Multiverses.Application
def get_and_wait(value) do
@application.put_env(:my_app, :env, value)
Process.sleep(1000)
@application.get_env(:my_app, :env)
end
end
defmodule SomeTest do
use ExUnit.Case, async: true
test do
assert :foo == MyModule.get_and_wait(:foo)
end
end
defmodule SomeOtherTest do
use ExUnit.Case, async: true
test do
assert :bar == MyModule.get_and_wait(:bar)
end
end
Link to this section Summary
Functions
Utility version of allow/3 that lets you batch-assign multiple allowances
Inspired by Mox.allow/3
, this function assigns a process or registered name process
to be put into the shard of a pid or directly into a shard.
Temporarily assigns the running process to the shard, within the scope of the provided lambda. This is done through the process dictionary. Other processes will not be aware that this process has been added to the shard.
Obtains the universe id for the current process.
Creates a new shard for a particular domain module and assigns this pid to the shard. You can batch assigning multiple shards as well.
Returns a list of multiverse domain modules and the respective shard-ids associated with those domain modules.
Link to this section Types
@type id() :: pos_integer()
Link to this section Functions
Utility version of allow/3 that lets you batch-assign multiple allowances
Inspired by Mox.allow/3
, this function assigns a process or registered name process
to be put into the shard of a pid or directly into a shard.
usage
usage
The following is the most common use case, called from the test process, where you want to allow a spawned process to be put into the same shard as the test process.
Multiverses.allow(Application, self(), child_pid)
In some cases you may want an allowance to occur from within the process that needs access to the shard. In this case, do the following:
Multiverses.allow(Application, multiverse_id, self())
Temporarily assigns the running process to the shard, within the scope of the provided lambda. This is done through the process dictionary. Other processes will not be aware that this process has been added to the shard.
Obtains the universe id for the current process.
This is found by checking process and the entries in the :$callers
process dictionary
entry to find if any of them are registered.
If the current process is not registered, then it raises Multiverses.UnexpectedCallError
options
Options
:strict
(defaults totrue
): iffalse
, returnsnil
, instead of crashing.
Creates a new shard for a particular domain module and assigns this pid to the shard. You can batch assigning multiple shards as well.
Returns a list of multiverse domain modules and the respective shard-ids associated with those domain modules.