# Sandbox modes in Ecto Testing

A **sandbox** is an isolated testing environment that enables users to run programs or open files without affecting the application, system or platform on which they run. Ecto provides a sandbox that wraps each test in a transaction, making sure the tests are isolated and can run concurrently.

There are a couple of modes in which the Ecto sandbox runs. When started, the sandbox pool is in automatic mode which means the Repo automatically grants connections to whoever needs them.
There are 2 other modes which are important to know as well. The first one is **manual** which is suitable for running async tests in. You usually set this mode in your test_helper.exs at the end of the file: 

```elixir 
ExUnit.start()
Ecto.Adapters.SQL.Sandbox.mode(SkepticBot.Repo, :manual)
```
In manual mode you have to explicitly allow another process to use the same connection if need be. Consider a case where you have a GenServer that does a resource update and you call it from inside the test: 

```elixir
    test "prediction handler uses the last message from Replicate to update the question",
         %{
           prediction_id: prediction_id,
           question: question,
           output: output
         } do
      send(PredictionHandler, {:register_prediction, prediction_id, {self(), question}})
      send(PredictionHandler, {:prediction_completed, prediction_id, output})

      question = Prompts.get_question(question.id)
      assert question.title == "The title"
      assert question.description == "The description"

      assert_receive {:prediction_result, {"The title", "The description"}}
    end
```
Here we are sending a message (:prediction_completed) to our GenServer **(PredictionHandler)** which does a database update using the *output* value. We will see the following in the logs : 
```bash
** (DBConnection.OwnershipError) cannot find ownership process for #PID<0.400.0>.

When using ownership, you must manage connections in one
of the four ways:
...
```
To solve this we need to allow our GenServer access to our connection using *allow/4*: 
```elixir
      allow = Process.whereis(PredictionHandler)
      Sandbox.allow(Repo, self(), allow)

      send(PredictionHandler, {:register_prediction, prediction_id, {self(), question}})
      send(PredictionHandler, {:prediction_completed, prediction_id, output})

      question = Prompts.get_question(question.id)
      assert question.title == "The title"
      assert question.description == "The description"

      assert_receive {:prediction_result, {"The title", "The description"}}
```
The last mode is the **shared** one. In this mode you will no longer have to allow individual processes access to the parent's connection. 
```elixir 
setup do
  # Explicitly get a connection before each test
  :ok = Sandbox.checkout(Repo)
  # Setting the shared mode must be done only after checkout
  Sandbox.mode(Repo, {:shared, self()})
end
```
The disadvantage of this mode is that you can no longer run your tests **concurrently**.



---

Created by: Deankinyua
Date: August 13, 2025
URL: https://elixirdrops.net/d/iyUsn9AL
